From 803fb243bfceecb4ecb054cb914a161411b2538a Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 7 Nov 2016 21:50:59 +0100 Subject: [PATCH 001/620] adding DNSMadeEasy API --- README.md | 1 + dnsapi/README.md | 19 ++++++ dnsapi/dns_me.sh | 148 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100755 dnsapi/dns_me.sh diff --git a/README.md b/README.md index 79b5a52f..104532bf 100644 --- a/README.md +++ b/README.md @@ -255,6 +255,7 @@ You don't have do anything manually! 8. 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.) 9. LuaDNS.com API +10. DNSMadeEasy.com API ##### More APIs are coming soon... diff --git a/dnsapi/README.md b/dnsapi/README.md index 19769111..7eff6de1 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -154,4 +154,23 @@ acme.sh --issue --dns dns_lua --dnssleep 3 -d example.com -d www.example.c The `LUA_Key` and `LUA_Email` will be saved in `~/.acme.sh/account.conf`, and will be reused when needed. +## Use DNSMadeEasy domain API + +Get your API credentials at https://cp.dnsmadeeasy.com/account/info + +``` +export ME_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" + +export ME_Secret="qdfqsdfkjdskfj" + +``` + +To issue a cert: +``` +acme.sh --issue --dns dns_me --dnssleep 3 -d example.com -d www.example.com +``` + +The `ME_Key` and `ME_Secret` will be saved in `~/.acme.sh/account.conf`, and will be reused when needed. + + diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh new file mode 100755 index 00000000..fffd8d49 --- /dev/null +++ b/dnsapi/dns_me.sh @@ -0,0 +1,148 @@ +#!/bin/sh + +# bug reports to dev@1e.ca + +# ME_Key=qmlkdjflmkqdjf +# ME_Secret=qmsdlkqmlksdvnnpae + +ME_Api=https://api.dnsmadeeasy.com/V2.0/dns/managed + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_me_add(){ + fulldomain=$1 + txtvalue=$2 + + if [ -z "$ME_Key" ] || [ -z "$ME_Secret" ] ; then + _err "You didn't specify DNSMadeEasy api key and secret yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf ME_Key "$ME_Key" + _saveaccountconf ME_Secret "$ME_Secret" + + _debug "First detect the root zone" + if ! _get_root $fulldomain ; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" + + if ! printf "$response" | grep \"totalRecords\": > /dev/null ; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o \"totalRecords\":[^,]* | cut -d : -f 2) + _debug count "$count" + if [ "$count" = "0" ] ; then + _info "Adding record" + if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then + if printf -- "%s" "$response" | grep id: > /dev/null ; then + _info "Added" + #todo: check if the record takes effect + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + record_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]* | cut -d : -f 2 | head -n 1) + _debug "record_id" $record_id + + _me_rest PUT "$_domain_id/records/$record_id/" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}" + if [ "$?" = "0" ]; then + _info "Updated" + #todo: check if the record takes effect + return 0; + fi + _err "Update error" + return 1 + fi + +} + + +#fulldomain +dns_me_rm() { + fulldomain=$1 + +} + + +#################### Private functions bellow ################################## +#_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 [ '1' ] ; do + h=$(printf $domain | cut -d . -f $i-100) + if [ -z "$h" ] ; then + #not valid + return 1; + fi + + if ! _me_rest GET "name?domainname=$h" ; then + return 1 + fi + + if printf $response | grep \"name\":\"$h\" >/dev/null ; then + _domain_id=$(printf "%s\n" "$response" | _egrep_o \"id\":[^,]* | head -n 1 | cut -d : -f 2 ) + if [ "$_domain_id" ] ; then + _sub_domain=$(printf $domain | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(expr $i + 1) + done + return 1 +} + +_me_rest() { + m=$1 + ep="$2" + data="$3" + _debug $ep + + cdate=$(date -Ru) + hmac=$(printf "$cdate" | openssl dgst -sha1 -hmac $ME_Secret | cut -d = -f 2 | tr -d ' ') + + _H1="x-dnsme-apiKey: $ME_Key" + _H2="x-dnsme-requestDate: $cdate" + _H3="x-dnsme-hmac: $hmac" + + if [ "$data" ] ; then + _debug data "$data" + response="$(_post "$data" "$ME_Api/$ep" "" $m)" + else + response="$(_get "$ME_Api/$ep")" + fi + + if [ "$?" != "0" ] ; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + + From 49e1f7d8bf8fc9b38918c03255badc5ccca1f383 Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 7 Nov 2016 22:16:00 +0100 Subject: [PATCH 002/620] bugfix --- dnsapi/dns_me.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index fffd8d49..4234ac9c 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -46,7 +46,7 @@ dns_me_add(){ if [ "$count" = "0" ] ; then _info "Adding record" if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then - if printf -- "%s" "$response" | grep id: > /dev/null ; then + if [ "$?" = "0" ]; then _info "Added" #todo: check if the record takes effect return 0 From 4fe7b6cd65df54833da378f3b2bec36b7c5202c2 Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 7 Nov 2016 22:16:53 +0100 Subject: [PATCH 003/620] better bugfix --- dnsapi/dns_me.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 4234ac9c..b379fe98 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -46,7 +46,7 @@ dns_me_add(){ if [ "$count" = "0" ] ; then _info "Adding record" if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then - if [ "$?" = "0" ]; then + if printf -- "%s" "$response" | grep \"id\": > /dev/null ; then _info "Added" #todo: check if the record takes effect return 0 From 0b5bff01e1a43cc531813c7a359e47735751a8aa Mon Sep 17 00:00:00 2001 From: nytral Date: Tue, 8 Nov 2016 14:13:05 +0100 Subject: [PATCH 004/620] s/bash/sh/ --- dnsapi/dns_me.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index b379fe98..d8dd7e45 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env sh # bug reports to dev@1e.ca From 22b83d76303eadfa05e6da859fa1e1b8ae769ea6 Mon Sep 17 00:00:00 2001 From: nytral Date: Tue, 8 Nov 2016 15:56:46 +0100 Subject: [PATCH 005/620] _hmac use and generic date --- dnsapi/dns_me.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index d8dd7e45..3135718e 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -123,8 +123,8 @@ _me_rest() { data="$3" _debug $ep - cdate=$(date -Ru) - hmac=$(printf "$cdate" | openssl dgst -sha1 -hmac $ME_Secret | cut -d = -f 2 | tr -d ' ') + cdate=$(date -u +"%a, %d %b %Y %T %Z") + hmac=$(printf "$cdate" | _hmac sha1 "$ME_Secret" 1) _H1="x-dnsme-apiKey: $ME_Key" _H2="x-dnsme-requestDate: $cdate" From 58bb94d7c73028441a3dfde7675a2150ae423685 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 25 Nov 2016 22:20:54 +0800 Subject: [PATCH 006/620] Update README.md --- dnsapi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index dbd27fce..c4245701 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -240,7 +240,7 @@ acme.sh --issue --dns dns_ispconfig -d example.com -d www.example.com The `ISPC_User`, `ISPC_Password`, `ISPC_Api`and `ISPC_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -# 13. Use custom API +# Use custom API If your API is not supported yet, you can write your own DNS API. @@ -257,6 +257,6 @@ 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) -## 14. Use lexicon DNS API +# Use lexicon DNS API https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api From 569d6c557c789a9ac749c9fe1b45ee606528fb23 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 29 Nov 2016 00:11:02 +0800 Subject: [PATCH 007/620] fix https://github.com/Neilpang/acme.sh/issues/426 --- acme.sh | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index bcaa3014..d886bfee 100755 --- a/acme.sh +++ b/acme.sh @@ -87,10 +87,13 @@ __red() { } _printargs() { + if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then + printf -- "%s" "[$(date)] " + fi if [ -z "$2" ]; then - printf -- "[$(date)] $1" + printf -- "%s" "$1" else - printf -- "%s" "[$(date)] $1='$2'" + printf -- "%s" "$1='$2'" fi printf "\n" } @@ -131,7 +134,9 @@ _info() { _err() { _log "$@" - printf -- "[$(date)] " >&2 + if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then + printf -- "%s" "[$(date)] " >&2 + fi if [ -z "$2" ]; then __red "$1" >&2 else @@ -3580,7 +3585,7 @@ _initconf() { #STAGE=1 # Use the staging api #FORCE=1 # Force to issue cert #DEBUG=1 # Debug mode - +#NO_TIMESTAMP=1 #OPENSSL_BIN=openssl #USER_AGENT=\"$USER_AGENT\" From b43416af97b3cc48625773a3635d694e2e923198 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 2 Dec 2016 20:24:12 +0800 Subject: [PATCH 008/620] do not use script home --- acme.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index d886bfee..c7c9f9f0 100755 --- a/acme.sh +++ b/acme.sh @@ -1612,14 +1612,14 @@ __initHome() { fi fi - if [ -z "$LE_WORKING_DIR" ]; then - if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then - _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" - LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" - else - LE_WORKING_DIR="$_SCRIPT_HOME" - fi - fi +# if [ -z "$LE_WORKING_DIR" ]; then +# if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then +# _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" +# LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" +# else +# LE_WORKING_DIR="$_SCRIPT_HOME" +# fi +# fi if [ -z "$LE_WORKING_DIR" ]; then _debug "Using default home:$DEFAULT_INSTALL_HOME" From 219e9115c03723d01dbb2eca6c26797875529842 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 2 Dec 2016 20:30:52 +0800 Subject: [PATCH 009/620] fix format --- acme.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index c7c9f9f0..a669aba1 100755 --- a/acme.sh +++ b/acme.sh @@ -1612,14 +1612,14 @@ __initHome() { fi fi -# if [ -z "$LE_WORKING_DIR" ]; then -# if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then -# _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" -# LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" -# else -# LE_WORKING_DIR="$_SCRIPT_HOME" -# fi -# fi + # if [ -z "$LE_WORKING_DIR" ]; then + # if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then + # _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" + # LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" + # else + # LE_WORKING_DIR="$_SCRIPT_HOME" + # fi + # fi if [ -z "$LE_WORKING_DIR" ]; then _debug "Using default home:$DEFAULT_INSTALL_HOME" From 048e5210f751b88104fb4455644e6d09815b0d18 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 2 Dec 2016 21:12:20 +0800 Subject: [PATCH 010/620] do not use script home * do not use script home * fix format --- acme.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/acme.sh b/acme.sh index d886bfee..a669aba1 100755 --- a/acme.sh +++ b/acme.sh @@ -1612,14 +1612,14 @@ __initHome() { fi fi - if [ -z "$LE_WORKING_DIR" ]; then - if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then - _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" - LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" - else - LE_WORKING_DIR="$_SCRIPT_HOME" - fi - fi + # if [ -z "$LE_WORKING_DIR" ]; then + # if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then + # _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" + # LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" + # else + # LE_WORKING_DIR="$_SCRIPT_HOME" + # fi + # fi if [ -z "$LE_WORKING_DIR" ]; then _debug "Using default home:$DEFAULT_INSTALL_HOME" From d69f0289caf15b1b8b8516a92b18ea68087024bc Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 4 Dec 2016 12:22:36 +0800 Subject: [PATCH 011/620] fix issue when there is no one records in the 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 0caf0c02..91556c67 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -69,11 +69,11 @@ existing_records() { _debug "Getting txt records" root=$1 sub=$2 - + count=0 if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then return 1 fi - count=0 + seg=$(printf "%s\n" "$response" | _egrep_o "{[^\{]*host\":\"$_sub_domain\"[^\}]*\}") _debug seg "$seg" if [ -z "$seg" ]; then From c572ce946bdbd56572d36d73a266a163e4396b54 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 4 Dec 2016 13:46:07 +0800 Subject: [PATCH 012/620] Dev (#434) * do not use script home * fix format * fix issue when there is no one records in the 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 0caf0c02..91556c67 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -69,11 +69,11 @@ existing_records() { _debug "Getting txt records" root=$1 sub=$2 - + count=0 if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then return 1 fi - count=0 + seg=$(printf "%s\n" "$response" | _egrep_o "{[^\{]*host\":\"$_sub_domain\"[^\}]*\}") _debug seg "$seg" if [ -z "$seg" ]; then From 5be3f22d06cd62397395b0de4e76f3f1d3c27405 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 4 Dec 2016 14:45:26 +0800 Subject: [PATCH 013/620] fix issue --- dnsapi/dns_cx.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 91556c67..ff1c943d 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -74,7 +74,7 @@ existing_records() { return 1 fi - seg=$(printf "%s\n" "$response" | _egrep_o "{[^\{]*host\":\"$_sub_domain\"[^\}]*\}") + seg=$(printf "%s\n" "$response" | _egrep_o '{[^{]*host":"'"$_sub_domain"'"[^}]*\}') _debug seg "$seg" if [ -z "$seg" ]; then return 0 @@ -82,7 +82,7 @@ existing_records() { if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then count=1 - record_id=$(printf "%s\n" "$seg" | _egrep_o "\"record_id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") + record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1) _debug record_id "$record_id" return 0 fi @@ -170,7 +170,7 @@ _get_root() { _rest() { m=$1 ep="$2" - _debug "$ep" + _debug ep "$ep" url="$REST_API/$ep" _debug url "$url" From e4468562d273863489558d4c89549b87e43c23eb Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 4 Dec 2016 21:24:38 +0800 Subject: [PATCH 014/620] fix cx --- dnsapi/dns_cx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 0c3d5c80..4117d29d 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -147,7 +147,7 @@ _get_root() { fi if _contains "$response" "$h."; then - seg=$(printf "%s" "$response" | _egrep_o '{[^{]*"'"$h"'."[^}]*}') + seg=$(echo "$response" | _egrep_o '{[^{]*"'"$h"'."[^}]*}') _debug seg "$seg" _domain_id=$(printf "%s" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" From a62706678e65f28deebe2ac58a7b19483089aaed Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 4 Dec 2016 21:33:36 +0800 Subject: [PATCH 015/620] fix for solaris --- 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 4117d29d..602a5012 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -147,9 +147,9 @@ _get_root() { fi if _contains "$response" "$h."; then - seg=$(echo "$response" | _egrep_o '{[^{]*"'"$h"'."[^}]*}') + seg=$(printf "%s\n" "$response" | _egrep_o '{[^{]*"'"$h"'."[^}]*}') _debug seg "$seg" - _domain_id=$(printf "%s" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") + _domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) From 8379f015d7e2280b4861478a086672d89dcabb37 Mon Sep 17 00:00:00 2001 From: kookxiang Date: Sat, 3 Dec 2016 23:32:50 +0800 Subject: [PATCH 016/620] Finish dns_cx_rm() method --- dnsapi/dns_cx.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 602a5012..86a7b2d0 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -58,7 +58,15 @@ dns_cx_add() { #fulldomain dns_cx_rm() { fulldomain=$1 - + REST_API="$CX_Api" + if _get_root "$fulldomain"; then + record_id="" + existing_records "$_domain" "$_sub_domain" + if ! [ "$record_id" = "" ]; then + _rest DELETE "record/$record_id/$_domain_id" "{}" + _info "Deleted record ${fulldomain}" + fi + fi } #usage: root sub From c12be766e92ec7cd97048f6ffbb8559c6e730ac7 Mon Sep 17 00:00:00 2001 From: Marcello Barnaba Date: Sun, 4 Dec 2016 20:10:33 +0100 Subject: [PATCH 017/620] Fix Route53 API consumer Ignoring the Chthlulu argument :smiley:, Route53 returns its XML all on one line, making not possible to grep the hosted zone record with egrep/sed. This change splits the XML in multiple lines, so that parsing can succeed. --- 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 15bf7b14..2c58754d 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -72,7 +72,7 @@ _get_root() { fi if _contains "$response" "$h."; then - hostedzone="$(echo "$response" | _egrep_o ".*$h..*")" + hostedzone="$(echo "$response" | sed 's//\n&/g' | _egrep_o ".*$h..*")" _debug hostedzone "$hostedzone" if [ -z "$hostedzone" ]; then _err "Error, can not get hostedzone." From eea52a5fa632eb87943cf1d84f880cf0043291a8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 13:55:06 +0800 Subject: [PATCH 018/620] update api template --- dnsapi/dns_myapi.sh | 38 +++++++++----------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh index 813a2ed1..f3e275d9 100755 --- a/dnsapi/dns_myapi.sh +++ b/dnsapi/dns_myapi.sh @@ -5,48 +5,28 @@ #So, here must be a method dns_myapi_add() #Which will be called by acme.sh to add the txt record to your api system. #returns 0 means success, otherwise error. - +# +#Author: Neilpang +#Report Bugs here: https://github.com/Neilpang/acme.sh +# ######## Public functions ##################### #Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_myapi_add() { fulldomain=$1 txtvalue=$2 + _info "Using myapi" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" _err "Not implemented!" return 1 } -#fulldomain +#Usage: fulldomain +#Remove the txt record afer validation. dns_myapi_rm() { fulldomain=$1 } #################### Private functions bellow ################################## -_info() { - if [ -z "$2" ]; then - echo "[$(date)] $1" - else - echo "[$(date)] $1='$2'" - fi -} - -_err() { - _info "$@" >&2 - return 1 -} - -_debug() { - if [ -z "$DEBUG" ]; then - return - fi - _err "$@" - return 0 -} - -_debug2() { - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - _debug "$@" - fi - return -} From e2d494321cc7ca58d423f1862c078f2549117fbb Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 14:02:31 +0800 Subject: [PATCH 019/620] update template --- .github/PULL_REQUEST_TEMPLATE.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2df6e9c4..29ea4e42 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,14 +1,9 @@ \ No newline at end of file From 21f201e37148c7ef2385621ca7b994388e9ab8d3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 14:58:36 +0800 Subject: [PATCH 020/620] support cloudflare rm function --- acme.sh | 5 +++-- dnsapi/dns_cf.sh | 43 ++++++++++++++++++++++++++++++++++++++----- dnsapi/dns_myapi.sh | 7 +++++-- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index a669aba1..9e3ae4b5 100755 --- a/acme.sh +++ b/acme.sh @@ -1991,7 +1991,8 @@ _clearupdns() { 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" | _urlencode)" + _debug txt "$txt" if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _info "$d is already verified, skip $vtype." continue @@ -2024,7 +2025,7 @@ _clearupdns() { txtdomain="_acme-challenge.$d" - if ! $rmcommand "$txtdomain"; then + if ! $rmcommand "$txtdomain" "$txt"; then _err "Error removing txt for domain:$txtdomain" return 1 fi diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index dd8c9143..6c191ead 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -55,9 +55,7 @@ dns_cf_add() { _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 - _info "Added, sleeping 10 seconds" - sleep 10 - #todo: check if the record takes effect + _info "Added, OK" return 0 else _err "Add txt record error." @@ -83,9 +81,44 @@ dns_cf_add() { } -#fulldomain +#fulldomain txtvalue dns_cf_rm() { fulldomain=$1 + txtvalue=$2 + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _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 } @@ -135,7 +168,7 @@ _cf_rest() { _H2="X-Auth-Key: $CF_Key" _H3="Content-Type: application/json" - if [ "$data" ]; then + if [ "$m" != "GET" ]; then _debug data "$data" response="$(_post "$data" "$CF_Api/$ep" "" "$m")" else diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh index f3e275d9..e5a98dd9 100755 --- a/dnsapi/dns_myapi.sh +++ b/dnsapi/dns_myapi.sh @@ -22,11 +22,14 @@ dns_myapi_add() { return 1 } -#Usage: fulldomain +#Usage: fulldomain txtvalue #Remove the txt record afer validation. dns_myapi_rm() { fulldomain=$1 - + txtvalue=$2 + _info "Using myapi" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" } #################### Private functions bellow ################################## From c0d0100ca8dd6c20abb29dded178fa41e8f449b9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 15:18:02 +0800 Subject: [PATCH 021/620] 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 6c191ead..b8ff06c1 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -101,7 +101,7 @@ dns_cf_rm() { _err "Error" return 1 fi - + count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) _debug count "$count" if [ "$count" = "0" ]; then From f162ad193fb29a304b2ef2e74141404fb2b6d7e2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 15:46:22 +0800 Subject: [PATCH 022/620] support dnspod remove --- dnsapi/dns_dp.sh | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index aa06d5fc..c6dd1ba3 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -6,9 +6,8 @@ # #DP_Key="sADDsdasdgdsf" -DP_Api="https://dnsapi.cn" +REST_API="https://dnsapi.cn" -#REST_API ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" @@ -24,8 +23,6 @@ dns_dp_add() { return 1 fi - REST_API="$DP_Api" - #save the api key and email to the account conf file. _saveaccountconf DP_Id "$DP_Id" _saveaccountconf DP_Key "$DP_Key" @@ -50,9 +47,39 @@ dns_dp_add() { fi } -#fulldomain +#fulldomain txtvalue dns_dp_rm() { fulldomain=$1 + txtvalue=$2 + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain"; then + _err "Record.Lis error." + return 1 + fi + + if _contains "$response" 'No records'; then + _info "Don't need to remove." + return 0 + fi + + record_id=$(echo "$response" | _egrep_o '{[^{]*"value":"'$txtvalue'"' | cut -d , -f 1 | cut -d : -f 2 | tr -d \") + _debug record_id "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id." + return 1 + fi + + if ! _rest POST "Record.Remove" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&record_id=$record_id"; then + _err "Record.Remove error." + return 1 + fi + + _contains "$response" "Action completed successful" } From f1f30743068610c1967fcf36b765e7a57f457844 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 15:54:19 +0800 Subject: [PATCH 023/620] fix format --- 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 c6dd1ba3..155979af 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -67,7 +67,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" | _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." From dfbc244b00cadf6b937171bce45a95641fb548df Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 16:52:02 +0800 Subject: [PATCH 024/620] support aws remove --- dnsapi/dns_aws.sh | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 2c58754d..ca79326b 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -49,9 +49,28 @@ dns_aws_add() { return 1 } -#fulldomain +#fulldomain txtvalue dns_aws_rm() { fulldomain=$1 + txtvalue=$2 + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _aws_tmpl_xml="DELETE\"$txtvalue\"$fulldomain.TXT300" + + if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then + _info "txt record deleted sucess." + return 0 + fi + + return 1 } From b9ece28f68bdf94018e9b40e921666dce653c565 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 19:02:46 +0800 Subject: [PATCH 025/620] add osx CI --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 859e8fe3..40dca816 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki |17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT) |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 +|20|[![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh)|OSX For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): From b28a3db3d6931c690bfb9d4f57a550a3dd98ec50 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 19:03:59 +0800 Subject: [PATCH 026/620] Mac OSX --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40dca816..1e563795 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki |17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT) |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 -|20|[![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh)|OSX +|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 [daily build project](https://github.com/Neilpang/acmetest): From 5efbaa48495d7380e170f575b805edfc8ad899b6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 6 Dec 2016 20:50:33 +0800 Subject: [PATCH 027/620] minor, clear default confs --- acme.sh | 50 -------------------------------------------------- 1 file changed, 50 deletions(-) diff --git a/acme.sh b/acme.sh index 9e3ae4b5..4c4a03f1 100755 --- a/acme.sh +++ b/acme.sh @@ -3569,23 +3569,16 @@ _initconf() { if [ ! -f "$ACCOUNT_CONF_PATH" ]; then echo "#ACCOUNT_CONF_PATH=xxxx -#Account configurations: -#Here are the supported macros, uncomment them to make them take effect. - #ACCOUNT_EMAIL=aaa@example.com # the account email used to register account. #ACCOUNT_KEY_PATH=\"/path/to/account.key\" #CERT_HOME=\"/path/to/cert/home\" - #LOG_FILE=\"$DEFAULT_LOG_FILE\" #LOG_LEVEL=1 #AUTO_UPGRADE=\"1\" -#STAGE=1 # Use the staging api -#FORCE=1 # Force to issue cert -#DEBUG=1 # Debug mode #NO_TIMESTAMP=1 #OPENSSL_BIN=openssl @@ -3593,49 +3586,6 @@ _initconf() { #USER_PATH= -#dns api -####################### -#Cloudflare: -#api key -#CF_Key=\"sdfsdfsdfljlbjkljlkjsdfoiwje\" -#account email -#CF_Email=\"xxxx@sss.com\" - -####################### -#Dnspod.cn: -#api key id -#DP_Id=\"1234\" -#api key -#DP_Key=\"sADDsdasdgdsf\" - -####################### -#Cloudxns.com: -#CX_Key=\"1234\" -# -#CX_Secret=\"sADDsdasdgdsf\" - -####################### -#Godaddy.com: -#GD_Key=\"sdfdsgdgdfdasfds\" -# -#GD_Secret=\"sADDsdasdfsdfdssdgdsf\" - -####################### -#nsupdate: -#NSUPDATE_KEY=\"/path/to/update.key\" -#NSUPDATE_SERVER=\"192.168.0.1\" - -####################### -#PowerDNS: -#PDNS_Url=\"http://ns.example.com:8081\" -#PDNS_ServerId=\"localhost\" -#PDNS_Token=\"0123456789ABCDEF\" -#PDNS_Ttl=60 - -####################### -#Amazon Route53: -#AWS_ACCESS_KEY_ID=XXXXXXXXXX -#AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXX " >"$ACCOUNT_CONF_PATH" fi From c7c57cfa0e7dc2ce77eaa542a342dc79fbab557a Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Dec 2016 11:49:24 +0800 Subject: [PATCH 028/620] fix for solaris --- 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 b8ff06c1..79f3ae83 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -144,7 +144,7 @@ _get_root() { fi if printf "%s" "$response" | grep "\"name\":\"$h\"" >/dev/null; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") + _domain_id=$(printf "%s\n" "$response" | _egrep_o "\[{\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain=$h From 122cc48c29be40b15122ae9ad2ddda026e0c2fa0 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Dec 2016 11:51:15 +0800 Subject: [PATCH 029/620] minor --- dnsapi/dns_cf.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 79f3ae83..309eee51 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -70,9 +70,7 @@ dns_cf_add() { _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" if [ "$?" = "0" ]; then - _info "Updated, sleeping 10 seconds" - sleep 10 - #todo: check if the record takes effect + _info "Updated, OK" return 0 fi _err "Update error" From 39d1eeda2362837b5eebc96a0d591573f1f0c744 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Dec 2016 12:41:22 +0800 Subject: [PATCH 030/620] fix for solaris --- dnsapi/dns_aws.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index ca79326b..63542ccb 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -91,13 +91,13 @@ _get_root() { fi if _contains "$response" "$h."; then - hostedzone="$(echo "$response" | sed 's//\n&/g' | _egrep_o ".*$h..*")" + hostedzone="$(echo "$response" | sed 's//\n&/g' | _egrep_o ".*$h.<.Name>.*<.HostedZone>")" _debug hostedzone "$hostedzone" if [ -z "$hostedzone" ]; then _err "Error, can not get hostedzone." return 1 fi - _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*" | head -n 1 | _egrep_o ">.*<" | tr -d "<>") + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>") if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain=$h From 7d1c5fca0b211168bc9e5f9cfe916f92c22f9fed Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Dec 2016 13:52:31 +0800 Subject: [PATCH 031/620] fix for solaris --- dnsapi/dns_dp.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 155979af..81edc225 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -102,7 +102,7 @@ existing_records() { fi if _contains "$response" "Action completed successful"; then - count=$(printf "%s" "$response" | grep 'TXT' | wc -l) + count=$(printf "%s" "$response" | grep 'TXT' | wc -l | tr -d ' ') record_id=$(printf "%s" "$response" | grep '^' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1) return 0 else @@ -208,9 +208,9 @@ _rest() { if [ "$data" ]; then _debug2 data "$data" - response="$(_post "$data" "$url")" + response="$(_post "$data" "$url" | tr -d '\r')" else - response="$(_get "$url")" + response="$(_get "$url" | tr -d '\r')" fi if [ "$?" != "0" ]; then From 2728170c01510e1c5ca5aaa9f06226f19819d5f3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Dec 2016 14:30:17 +0800 Subject: [PATCH 032/620] add debug info --- dnsapi/dns_dp.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 81edc225..e2952d71 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -104,6 +104,7 @@ existing_records() { if _contains "$response" "Action completed successful"; then count=$(printf "%s" "$response" | grep 'TXT' | wc -l | tr -d ' ') record_id=$(printf "%s" "$response" | grep '^' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1) + _debug record_id "$record_id" return 0 else _err "get existing records error." From 03d3f3afc39e688bb998f8e2f7d3c094a2aad1df Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 7 Dec 2016 14:50:45 +0800 Subject: [PATCH 033/620] fix for solaris --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4c4a03f1..5e672a59 100755 --- a/acme.sh +++ b/acme.sh @@ -3469,7 +3469,7 @@ _deactivate() { return 1 fi - entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"status":"valid","uri"[^\}]*')" + entry="$(printf "%s\n" "$response" | _egrep_o '{"type":".*","status":"valid","uri"[^}]*')" _debug entry "$entry" if [ -z "$entry" ]; then From 947d14ffebe9ce35ccc5da9e61a0469cfb99efb8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 9 Dec 2016 22:20:38 +0800 Subject: [PATCH 034/620] fix deactivate function --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5e672a59..dc3ac7f0 100755 --- a/acme.sh +++ b/acme.sh @@ -3469,7 +3469,7 @@ _deactivate() { return 1 fi - entry="$(printf "%s\n" "$response" | _egrep_o '{"type":".*","status":"valid","uri"[^}]*')" + entry="$(printf "%s\n" "$response" | _egrep_o '{"type":"[^"]*","status":"valid","uri"[^}]*')" _debug entry "$entry" if [ -z "$entry" ]; then From c4236e58d1d8faf3491335e48b43e3fdc1112a9c Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 10 Dec 2016 21:32:47 +0800 Subject: [PATCH 035/620] fix renew for different CA --- acme.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/acme.sh b/acme.sh index dc3ac7f0..6803616a 100755 --- a/acme.sh +++ b/acme.sh @@ -529,6 +529,7 @@ _isEccKey() { _createkey() { length="$1" f="$2" + _debug2 "_createkey for file:$f" eccname="$length" if _startswith "$length" "ec-"; then length=$(printf "%s" "$length" | cut -d '-' -f 2-100) @@ -1685,6 +1686,7 @@ _initpath() { if [ -z "$CA_CONF" ]; then CA_CONF="$_DEFAULT_CA_CONF" fi + _debug3 CA_CONF "$CA_CONF" if [ -f "$CA_CONF" ]; then . "$CA_CONF" @@ -2990,6 +2992,12 @@ renew() { if [ "$Le_API" ]; then API="$Le_API" + #reload ca configs + ACCOUNT_KEY_PATH="" + ACCOUNT_JSON_PATH="" + CA_CONF="" + _debug3 "initpath again." + _initpath "$Le_Domain" "$_isEcc" fi if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then From 4d8b99a3073778fb387a2ffa02198db835912331 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 13 Dec 2016 20:04:43 +0800 Subject: [PATCH 036/620] add more debug info --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index 6803616a..436c3ef9 100755 --- a/acme.sh +++ b/acme.sh @@ -406,8 +406,10 @@ _getfile() { #Usage: multiline _base64() { if [ "$1" ]; then + _debug3 "base64 multiline:$1" $OPENSSL_BIN base64 -e else + _debug3 "base64 single line." $OPENSSL_BIN base64 -e | tr -d '\r\n' fi } @@ -932,6 +934,8 @@ _calcjwk() { modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" + _debug3 n "$n" + jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' _debug3 jwk "$jwk" From 24d2a8b9d52facff65e999a8a668c3720b2dbbb7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 13 Dec 2016 20:27:49 +0800 Subject: [PATCH 037/620] add debug info --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 436c3ef9..33c0ed4a 100755 --- a/acme.sh +++ b/acme.sh @@ -406,7 +406,7 @@ _getfile() { #Usage: multiline _base64() { if [ "$1" ]; then - _debug3 "base64 multiline:$1" + _debug3 "base64 multiline:'$1'" $OPENSSL_BIN base64 -e else _debug3 "base64 single line." @@ -933,7 +933,7 @@ _calcjwk() { modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" - n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" + n="$(printf "%s" "$modulus" | _h2b | _base64| _urlencode)" _debug3 n "$n" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' From 1f6ffa3e88c8b0719d26943aa3b065571c47140b Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 13 Dec 2016 20:32:50 +0800 Subject: [PATCH 038/620] fix warnings --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 33c0ed4a..c6af629a 100755 --- a/acme.sh +++ b/acme.sh @@ -933,7 +933,7 @@ _calcjwk() { modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" - n="$(printf "%s" "$modulus" | _h2b | _base64| _urlencode)" + n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" _debug3 n "$n" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' From b171aff4189634387be9fefbff64f716582136a4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 13 Dec 2016 20:42:36 +0800 Subject: [PATCH 039/620] fix for wrt https://github.com/Neilpang/acme.sh/issues/465 I know it's a stupid fix, but it works. I will check it later. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index c6af629a..3512b8d6 100755 --- a/acme.sh +++ b/acme.sh @@ -933,7 +933,7 @@ _calcjwk() { modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" - n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" + n="$(printf "%s" "$modulus" | _h2b | _base64 | tr -d '\r\n' | _urlencode)" _debug3 n "$n" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' From 329174b6d93b04cd239878f3fda07458532f7b29 Mon Sep 17 00:00:00 2001 From: klemens Date: Wed, 14 Dec 2016 21:32:24 +0100 Subject: [PATCH 040/620] spelling fixes --- README.md | 2 +- acme.sh | 4 ++-- dnsapi/dns_ali.sh | 2 +- dnsapi/dns_aws.sh | 6 +++--- dnsapi/dns_cf.sh | 2 +- dnsapi/dns_cx.sh | 2 +- dnsapi/dns_dp.sh | 2 +- dnsapi/dns_gd.sh | 2 +- dnsapi/dns_ispconfig.sh | 2 +- dnsapi/dns_lua.sh | 2 +- dnsapi/dns_me.sh | 2 +- dnsapi/dns_myapi.sh | 4 ++-- dnsapi/dns_nsupdate.sh | 2 +- dnsapi/dns_ovh.sh | 2 +- dnsapi/dns_pdns.sh | 2 +- 15 files changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 1e563795..a9d5d31d 100644 --- a/README.md +++ b/README.md @@ -321,7 +321,7 @@ acme.sh --renew -d example.com --force --ecc # 11. How to upgrade `acme.sh` -acme.sh is in constant developement, so it's strongly recommended to use the latest code. +acme.sh is in constant development, so it's strongly recommended to use the latest code. You can update acme.sh to the latest code: diff --git a/acme.sh b/acme.sh index 6803616a..75d4be80 100755 --- a/acme.sh +++ b/acme.sh @@ -1913,7 +1913,7 @@ _setApache() { fi _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" _info "In case there is an error that can not be restored automatically, you may try restore it yourself." - _info "The backup file will be deleted on sucess, just forget it." + _info "The backup file will be deleted on success, just forget it." #add alias @@ -3780,7 +3780,7 @@ install() { if [ -z "$NO_DETECT_SH" ]; then #Modify shebang if _exists bash; then - _info "Good, bash is found, so change the shebang to use bash as prefered." + _info "Good, bash is found, so change the shebang to use bash as preferred." _shebang='#!/usr/bin/env bash' _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" for subf in $_SUB_FOLDERS; do diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh index 30867219..98c56f87 100644 --- a/dnsapi/dns_ali.sh +++ b/dnsapi/dns_ali.sh @@ -35,7 +35,7 @@ dns_ali_rm() { _clean } -#################### Private functions bellow ################################## +#################### Private functions below ################################## _get_root() { domain=$1 diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 63542ccb..86d4d044 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -42,7 +42,7 @@ dns_aws_add() { _aws_tmpl_xml="UPSERT$fulldomainTXT300\"$txtvalue\"" if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then - _info "txt record updated sucess." + _info "txt record updated success." return 0 fi @@ -66,7 +66,7 @@ dns_aws_rm() { _aws_tmpl_xml="DELETE\"$txtvalue\"$fulldomain.TXT300" if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then - _info "txt record deleted sucess." + _info "txt record deleted success." return 0 fi @@ -74,7 +74,7 @@ dns_aws_rm() { } -#################### Private functions bellow ################################## +#################### Private functions below ################################## _get_root() { domain=$1 diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 309eee51..e13e6d7e 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -120,7 +120,7 @@ dns_cf_rm() { } -#################### Private functions bellow ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 86a7b2d0..f7f20812 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -131,7 +131,7 @@ update_record() { return 1 } -#################### Private functions bellow ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index e2952d71..06833b4b 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -158,7 +158,7 @@ update_record() { return 1 #error } -#################### Private functions bellow ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 9470ed22..81000561 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -59,7 +59,7 @@ dns_gd_rm() { } -#################### Private functions bellow ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www diff --git a/dnsapi/dns_ispconfig.sh b/dnsapi/dns_ispconfig.sh index 789b6267..a84d95d7 100755 --- a/dnsapi/dns_ispconfig.sh +++ b/dnsapi/dns_ispconfig.sh @@ -30,7 +30,7 @@ dns_ispconfig_rm() { _ISPC_credentials && _ISPC_login && _ISPC_rmTxt } -#################### Private functions bellow ################################## +#################### Private functions below ################################## _ISPC_credentials() { if [ -z "${ISPC_User}" ] || [ -z "$ISPC_Password" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 2c7ec4b3..bc06b3ef 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -84,7 +84,7 @@ dns_lua_rm() { } -#################### Private functions bellow ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 2a03f533..d7a1b19f 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -81,7 +81,7 @@ dns_me_rm() { } -#################### Private functions bellow ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _sub_domain=_acme-challenge.www diff --git a/dnsapi/dns_myapi.sh b/dnsapi/dns_myapi.sh index e5a98dd9..6bf62508 100755 --- a/dnsapi/dns_myapi.sh +++ b/dnsapi/dns_myapi.sh @@ -23,7 +23,7 @@ dns_myapi_add() { } #Usage: fulldomain txtvalue -#Remove the txt record afer validation. +#Remove the txt record after validation. dns_myapi_rm() { fulldomain=$1 txtvalue=$2 @@ -32,4 +32,4 @@ dns_myapi_rm() { _debug txtvalue "$txtvalue" } -#################### Private functions bellow ################################## +#################### Private functions below ################################## diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index 8067d2fe..7acb2ef7 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -44,7 +44,7 @@ EOF return 0 } -#################### Private functions bellow ################################## +#################### Private functions below ################################## _checkKeyFile() { if [ -z "${NSUPDATE_KEY}" ]; then diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 377b3de1..18b9c341 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -182,7 +182,7 @@ dns_ovh_rm() { } -#################### Private functions bellow ################################## +#################### Private functions below ################################## _ovh_authentication() { diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index a2c29075..06763d88 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -130,7 +130,7 @@ notify_slaves() { return 0 } -#################### Private functions bellow ################################## +#################### Private functions below ################################## #_acme-challenge.www.domain.com #returns # _domain=domain.com From a3a04b5f769f58514cce19933b44b73e798bbc5f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Dec 2016 20:51:00 +0800 Subject: [PATCH 041/620] revert last fix --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 3512b8d6..c6af629a 100755 --- a/acme.sh +++ b/acme.sh @@ -933,7 +933,7 @@ _calcjwk() { modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" - n="$(printf "%s" "$modulus" | _h2b | _base64 | tr -d '\r\n' | _urlencode)" + n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" _debug3 n "$n" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' From 96db9362c565cd9245b0051af50ab08f1b195eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Sun, 18 Dec 2016 03:17:35 +0100 Subject: [PATCH 042/620] Fix typo. --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 81e0e0cc..acbcc023 100755 --- a/acme.sh +++ b/acme.sh @@ -637,8 +637,8 @@ _createcsr() { _info "Multi domain" "$alt" printf -- "\nsubjectAltName=$alt" >>"$csrconf" fi - if [ "$Le_OCSP_Stable" ]; then - _savedomainconf Le_OCSP_Stable "$Le_OCSP_Stable" + if [ "$Le_OCSP_Staple" ]; then + _savedomainconf Le_OCSP_Staple "$Le_OCSP_Staple" printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf" fi @@ -4365,7 +4365,7 @@ _process() { shift ;; --ocsp-must-staple | --ocsp) - Le_OCSP_Stable="1" + Le_OCSP_Staple="1" ;; --log | --logfile) _log="1" From 0a3b6c4813b9faa1b5f7404455a4876972b052b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Sun, 18 Dec 2016 05:29:27 +0100 Subject: [PATCH 043/620] Keep backwards compatible. --- acme.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index acbcc023..b67960d0 100755 --- a/acme.sh +++ b/acme.sh @@ -637,8 +637,9 @@ _createcsr() { _info "Multi domain" "$alt" printf -- "\nsubjectAltName=$alt" >>"$csrconf" fi - if [ "$Le_OCSP_Staple" ]; then + if [ "$Le_OCSP_Staple" ] || [ "$Le_OCSP_Stable" ]; then _savedomainconf Le_OCSP_Staple "$Le_OCSP_Staple" + _cleardomainconf Le_OCSP_Stable printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf" fi From 08b6cf023169788404ac05baf23e6017adaa7767 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 21 Dec 2016 19:56:28 +0800 Subject: [PATCH 044/620] fix https://github.com/Neilpang/acme.sh/issues/478 --- acme.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/acme.sh b/acme.sh index b67960d0..691eb7d8 100755 --- a/acme.sh +++ b/acme.sh @@ -2225,11 +2225,13 @@ _regAccount() { _reg_length="$1" if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then + mkdir -p "$CA_DIR" _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 + mkdir -p "$CA_DIR" _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" fi From e2c939fb97da2dcd578e6aff0acec4b008afde11 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 21 Dec 2016 20:19:57 +0800 Subject: [PATCH 045/620] fix https://github.com/Neilpang/acme.sh/issues/480 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 691eb7d8..a4375033 100755 --- a/acme.sh +++ b/acme.sh @@ -3359,7 +3359,7 @@ installcronjob() { _err "Can not install cronjob, $PROJECT_ENTRY not found." return 1 fi - if _exists uname && uname -a | grep solaris >/dev/null; then + if _exists uname && uname -a | grep SunOS >/dev/null; then crontab -l | { cat echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" From 3a3b0dd5c1b5a8d9ec7c45f42194c5ae56a44cf8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 21 Dec 2016 20:38:14 +0800 Subject: [PATCH 046/620] fix https://github.com/Neilpang/acme.sh/issues/481 --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index a4375033..aefc0155 100755 --- a/acme.sh +++ b/acme.sh @@ -3977,7 +3977,10 @@ _installOnline() { fi ( _info "Extracting $localname" - tar xzf $localname + if ! (tar xzf $localname || gtar xzf $localname); then + _err "Extraction error." + exit 1 + fi cd "$PROJECT_NAME-$BRANCH" chmod +x $PROJECT_ENTRY From 4743171b4f1f97c4054f4df6365f44630ee65753 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 22 Dec 2016 20:06:55 +0800 Subject: [PATCH 047/620] service nginx force-reload --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a9d5d31d..1a7766ef 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ acme.sh --installcert -d example.com \ --certpath /path/to/certfile/in/apache/cert.pem \ --keypath /path/to/keyfile/in/apache/key.pem \ --fullchainpath /path/to/fullchain/certfile/apache/fullchain.pem \ ---reloadcmd "service apache2 restart" +--reloadcmd "service apache2 force-reload" ``` **Nginx** example: @@ -155,7 +155,7 @@ acme.sh --installcert -d example.com \ acme.sh --installcert -d example.com \ --keypath /path/to/keyfile/in/nginx/key.pem \ --fullchainpath /path/to/fullchain/nginx/cert.pem \ ---reloadcmd "service nginx restart" +--reloadcmd "service nginx force-reload" ``` Only the domain is required, all the other parameters are optional. From 8c71bd57e750ee1ad827d706c02bfa3052d18076 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 27 Dec 2016 20:19:22 +0800 Subject: [PATCH 048/620] fix https://github.com/Neilpang/acme.sh/issues/491 --- 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 f7f20812..dfc838ae 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -82,7 +82,7 @@ existing_records() { return 1 fi - seg=$(printf "%s\n" "$response" | _egrep_o '{[^{]*host":"'"$_sub_domain"'"[^}]*\}') + seg=$(printf "%s\n" "$response" | _egrep_o '[^{]*host":"'"$_sub_domain"'"[^}]*\}') _debug seg "$seg" if [ -z "$seg" ]; then return 0 @@ -155,7 +155,7 @@ _get_root() { fi if _contains "$response" "$h."; then - seg=$(printf "%s\n" "$response" | _egrep_o '{[^{]*"'"$h"'."[^}]*}') + seg=$(printf "%s\n" "$response" | _egrep_o '[^{]*"'"$h"'."[^}]*}') _debug seg "$seg" _domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" From 15af89d51cdd7c64705471550dc8ade17713eec8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 27 Dec 2016 20:40:52 +0800 Subject: [PATCH 049/620] fix https://github.com/Neilpang/acme.sh/issues/490 --- dnsapi/dns_cf.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index e13e6d7e..0b817d36 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -132,6 +132,7 @@ _get_root() { 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 @@ -141,8 +142,8 @@ _get_root() { return 1 fi - if printf "%s" "$response" | grep "\"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 "$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 From 20444bf253841de76fedc80de824665aa0eafa61 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 27 Dec 2016 20:53:57 +0800 Subject: [PATCH 050/620] fix https://github.com/Neilpang/acme.sh/issues/465 --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index aefc0155..4c096534 100755 --- a/acme.sh +++ b/acme.sh @@ -405,6 +405,7 @@ _getfile() { #Usage: multiline _base64() { + [ "" ];#urgly if [ "$1" ]; then _debug3 "base64 multiline:'$1'" $OPENSSL_BIN base64 -e From ec9975c3d9a521ebcf3573841810adfaa58a08c4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 27 Dec 2016 21:29:44 +0800 Subject: [PATCH 051/620] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4c096534..5199a820 100755 --- a/acme.sh +++ b/acme.sh @@ -405,7 +405,7 @@ _getfile() { #Usage: multiline _base64() { - [ "" ];#urgly + [ "" ] #urgly if [ "$1" ]; then _debug3 "base64 multiline:'$1'" $OPENSSL_BIN base64 -e From fe600441c9a121e0b6bdf125296f316d2b44d67c Mon Sep 17 00:00:00 2001 From: Georg Lutz Date: Thu, 29 Dec 2016 11:12:26 +0100 Subject: [PATCH 052/620] Add note about permissions of installed files --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1a7766ef..dde2eeae 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,8 @@ acme.sh --installcert -d example.com \ Only the domain is required, all the other parameters are optional. +The ownership and permission info of existing files are preserved. You may want to precreate the files to have defined ownership and permission. + Install/copy the issued cert/key to the production Apache or Nginx path. The cert will be `renewed every **60** days by default` (which is configurable). Once the cert is renewed, the Apache/Nginx service will be restarted automatically by the command: `service apache2 restart` or `service nginx restart`. From e5079b9dad0b8e12d4d043daacd5da93e8422d4a Mon Sep 17 00:00:00 2001 From: Paul Koppen Date: Mon, 2 Jan 2017 23:39:00 +0000 Subject: [PATCH 053/620] Add Alwaysdata DNS API. --- dnsapi/dns_ad.sh | 139 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 dnsapi/dns_ad.sh diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh new file mode 100644 index 00000000..158ea951 --- /dev/null +++ b/dnsapi/dns_ad.sh @@ -0,0 +1,139 @@ +#!/usr/bin/env sh + +# +#AD_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" + +#This is the Alwaysdata api wrapper for acme.sh + +AD_HOST="api.alwaysdata.com" +AD_URL="https://$AD_API_KEY:@$AD_HOST" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_ad_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$AD_API_KEY" ]; then + AD_API_KEY="" + _err "You didn't specify the AD api key yet." + _err "Please create you key and try again." + return 1 + fi + + _saveaccountconf AD_API_KEY "$AD_API_KEY" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _ad_tmpl_json="{\"domain\":$_domain_id,\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\"}" + + if ad_rest POST "record/" "" "$_ad_tmpl_json" && [ -z "$response" ]; then + _info "txt record updated success." + return 0 + fi + + return 1 +} + +#fulldomain txtvalue +dns_ad_rm() { + fulldomain=$1 + txtvalue=$2 + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if ad_rest DELETE "record/" "domain=$_domain_id&name=$_sub_domain" "" && [ -z "$response" ]; then + _info "txt record deleted success." + return 0 + fi + _debug response "$response" + + return 1 +} + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + i=2 + p=1 + + if ad_rest GET "domain/"; then + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "$h"; then + hostedzone="$(echo "$response" | tr -d "\n" | sed 's//\n&/g' | _egrep_o ".*$h<.name>.*<.object>")" + if [ -z "$hostedzone" ]; then + _err "Error, can not get domain record." + return 1 + fi + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*<.id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>") + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + fi + return 1 +} + +#method uri qstr data +ad_rest() { + mtd="$1" + ep="$2" + qsr="$3" + data="$4" + + _debug mtd "$mtd" + _debug ep "$ep" + _debug qsr "$qsr" + _debug data "$data" + + _H1="Accept: application/xml" + + url="$AD_URL/v1/$ep?$qsr" + + if [ "$mtd" = "GET" ]; then + response="$(_get "$url")" + elif [ "$mtd" = "DELETE" ]; then + response="$(_delete "$url")" + else + response="$(_post "$data" "$url")" + fi + + _ret="$?" + if [ "$_ret" = "0" ]; then + # Errors usually 404, otherwise just empty response. How to detect 404? + if _contains "$response" " Date: Tue, 3 Jan 2017 19:31:11 +0800 Subject: [PATCH 054/620] run pre-hook first --- acme.sh | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/acme.sh b/acme.sh index 5199a820..06b14ef6 100755 --- a/acme.sh +++ b/acme.sh @@ -2075,6 +2075,17 @@ _clearupwebbroot() { _on_before_issue() { _debug _on_before_issue + #run pre hook + if [ "$Le_PreHook" ]; then + _info "Run pre hook:'$Le_PreHook'" + if ! ( + cd "$DOMAIN_PATH" && eval "$Le_PreHook" + ); then + _err "Error when run pre hook." + return 1 + fi + fi + if _hasfield "$Le_Webroot" "$NO_VALUE"; then if ! _exists "nc"; then _err "Please install netcat(nc) tools first." @@ -2142,16 +2153,6 @@ _on_before_issue() { usingApache="" fi - #run pre hook - if [ "$Le_PreHook" ]; then - _info "Run pre hook:'$Le_PreHook'" - if ! ( - cd "$DOMAIN_PATH" && eval "$Le_PreHook" - ); then - _err "Error when run pre hook." - return 1 - fi - fi } _on_issue_err() { From 331b599a8184234f3f007acfca570ce43b26e31c Mon Sep 17 00:00:00 2001 From: Paul Koppen Date: Tue, 3 Jan 2017 11:41:11 +0000 Subject: [PATCH 055/620] Use _post for DELETE and switch to JSON API (Alwaysdata default). --- dnsapi/dns_ad.sh | 81 +++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index 158ea951..379b51f9 100644 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -5,8 +5,7 @@ #This is the Alwaysdata api wrapper for acme.sh -AD_HOST="api.alwaysdata.com" -AD_URL="https://$AD_API_KEY:@$AD_HOST" +AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1" ######## Public functions ##################### @@ -35,7 +34,7 @@ dns_ad_add() { _ad_tmpl_json="{\"domain\":$_domain_id,\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\"}" - if ad_rest POST "record/" "" "$_ad_tmpl_json" && [ -z "$response" ]; then + if _ad_rest POST "record/" "$_ad_tmpl_json" && [ -z "$response" ]; then _info "txt record updated success." return 0 fi @@ -57,37 +56,51 @@ dns_ad_rm() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - if ad_rest DELETE "record/" "domain=$_domain_id&name=$_sub_domain" "" && [ -z "$response" ]; then - _info "txt record deleted success." - return 0 + _debug "Getting txt records" + _ad_rest GET "record/?domain=$_domain_id&name=$_sub_domain" + + if [ -n "$response" ]; then + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d \ | head -n 1) + _debug record_id "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if _ad_rest DELETE "record/$record_id/" && [ -z "$response" ]; then + _info "txt record deleted success." + return 0 + fi + _debug response "$response" + return 1 fi - _debug response "$response" return 1 } #################### Private functions below ################################## - +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=12345 _get_root() { domain=$1 i=2 p=1 - if ad_rest GET "domain/"; then + if _ad_rest GET "domain/"; then + response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" if [ -z "$h" ]; then #not valid return 1 fi - if _contains "$response" "$h"; then - hostedzone="$(echo "$response" | tr -d "\n" | sed 's//\n&/g' | _egrep_o ".*$h<.name>.*<.object>")" - if [ -z "$hostedzone" ]; then - _err "Error, can not get domain record." - return 1 - fi - _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*<.id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>") + hostedzone="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$h\".*}")" + if [ "$hostedzone" ]; then + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | head -n 1 | cut -d : -f 2 | tr -d \ ) if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain=$h @@ -103,37 +116,29 @@ _get_root() { } #method uri qstr data -ad_rest() { +_ad_rest() { mtd="$1" ep="$2" - qsr="$3" - data="$4" + data="$3" _debug mtd "$mtd" _debug ep "$ep" - _debug qsr "$qsr" - _debug data "$data" - _H1="Accept: application/xml" + _H1="Accept: application/json" + _H2="Content-Type: application/json" - url="$AD_URL/v1/$ep?$qsr" - - if [ "$mtd" = "GET" ]; then - response="$(_get "$url")" - elif [ "$mtd" = "DELETE" ]; then - response="$(_delete "$url")" + if [ "$mtd" != "GET" ]; then + # both POST and DELETE. + _debug data "$data" + response="$(_post "$data" "$AD_API_URL/$ep" "" "$mtd")" else - response="$(_post "$data" "$url")" + response="$(_get "$AD_API_URL/$ep")" fi - _ret="$?" - if [ "$_ret" = "0" ]; then - # Errors usually 404, otherwise just empty response. How to detect 404? - if _contains "$response" " Date: Tue, 3 Jan 2017 12:09:57 +0000 Subject: [PATCH 056/620] Merge suggested improvements. * Use `_head_n`. * Add link to GitHub repo for bug reporting. --- dnsapi/dns_ad.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index 379b51f9..81c20e09 100644 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -4,6 +4,9 @@ #AD_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" #This is the Alwaysdata api wrapper for acme.sh +# +#Author: Paul Koppen +#Report Bugs here: https://github.com/wpk-/acme.sh AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1" @@ -60,7 +63,7 @@ dns_ad_rm() { _ad_rest GET "record/?domain=$_domain_id&name=$_sub_domain" if [ -n "$response" ]; then - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d \ | head -n 1) + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d \ | _head_n 1) _debug record_id "$record_id" if [ -z "$record_id" ]; then _err "Can not get record id to remove." @@ -100,7 +103,7 @@ _get_root() { hostedzone="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$h\".*}")" if [ "$hostedzone" ]; then - _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | head -n 1 | cut -d : -f 2 | tr -d \ ) + _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 From b2686e5b6da57b51f2ddb55e8ca06e69777c8cab Mon Sep 17 00:00:00 2001 From: Paul Koppen Date: Tue, 3 Jan 2017 12:13:27 +0000 Subject: [PATCH 057/620] Add Alwaysdata.com to list of supported API's. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dde2eeae..9b5891c9 100644 --- a/README.md +++ b/README.md @@ -265,6 +265,7 @@ You don't have to do anything manually! 1. nsupdate API 1. aliyun.com(阿里云) API 1. ISPConfig 3.1 API +1. Alwaysdata.com API **More APIs coming soon...** From 180f05f6f08bdfbec46d53c6b1b4bdcc7538e527 Mon Sep 17 00:00:00 2001 From: Paul Koppen Date: Tue, 3 Jan 2017 12:16:22 +0000 Subject: [PATCH 058/620] Add instructions for the Alwaysdata API. --- dnsapi/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index c4245701..e32b4655 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -240,6 +240,23 @@ acme.sh --issue --dns dns_ispconfig -d example.com -d www.example.com The `ISPC_User`, `ISPC_Password`, `ISPC_Api`and `ISPC_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 13. Use Alwaysdata domain API + +First you need to login to your Alwaysdata account to get your API Key. + +```sh +export AD_API_KEY="myalwaysdataapikey" +``` + +Ok, let's issue a cert now: + +```sh +acme.sh --issue --dns dns_ad -d example.com -d www.example.com +``` + +The `AD_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused +when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. From b90917a52951e85cb5eda4ae51d6daedd921fbf7 Mon Sep 17 00:00:00 2001 From: Paul Koppen Date: Tue, 3 Jan 2017 12:33:10 +0000 Subject: [PATCH 059/620] Improve legibility. --- dnsapi/dns_ad.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index 81c20e09..cbec6c9b 100644 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -63,7 +63,7 @@ dns_ad_rm() { _ad_rest GET "record/?domain=$_domain_id&name=$_sub_domain" if [ -n "$response" ]; then - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d \ | _head_n 1) + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) _debug record_id "$record_id" if [ -z "$record_id" ]; then _err "Can not get record id to remove." From 7b4be7be4094176098d889d7a37feab0dd45ace9 Mon Sep 17 00:00:00 2001 From: Paul Koppen Date: Tue, 3 Jan 2017 12:35:10 +0000 Subject: [PATCH 060/620] Remove spaces from blank lines. --- dnsapi/dns_ad.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index cbec6c9b..1c7e85f9 100644 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -36,12 +36,12 @@ dns_ad_add() { _debug _domain "$_domain" _ad_tmpl_json="{\"domain\":$_domain_id,\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\"}" - + if _ad_rest POST "record/" "$_ad_tmpl_json" && [ -z "$response" ]; then _info "txt record updated success." return 0 fi - + return 1 } @@ -61,7 +61,7 @@ dns_ad_rm() { _debug "Getting txt records" _ad_rest GET "record/?domain=$_domain_id&name=$_sub_domain" - + if [ -n "$response" ]; then record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) _debug record_id "$record_id" @@ -129,7 +129,7 @@ _ad_rest() { _H1="Accept: application/json" _H2="Content-Type: application/json" - + if [ "$mtd" != "GET" ]; then # both POST and DELETE. _debug data "$data" From 058e5d5f4b9b67f49527da71f9c0a3fbfbecc8c4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 5 Jan 2017 22:32:26 +0800 Subject: [PATCH 061/620] LF --- .travis.yml | 108 ++++++++++++++++++++++++++-------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/.travis.yml b/.travis.yml index 94848c17..0667919d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,54 +1,54 @@ -language: shell -sudo: required - -os: - - linux - - osx - -env: - global: - - SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64 - -addons: - apt: - sources: - - debian-sid # Grab shellcheck from the Debian repo (o_O) - packages: - - shellcheck - -install: - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - brew update && brew install openssl; - brew info openssl; - ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; - ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; - ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl; - _old_path="$PATH"; - echo "PATH=$PATH"; - export PATH=""; - export OPENSSL_BIN="/usr/local/openssl"; - openssl version 2>&1 || true; - $OPENSSL_BIN version 2>&1 || true; - export PATH="$_old_path"; - fi - -script: - - echo "TEST_LOCAL=$TEST_LOCAL" - - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - - which openssl && openssl version - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod +x ~/shfmt ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi - - cd .. - - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi - - -matrix: - fast_finish: true - - +language: shell +sudo: required + +os: + - linux + - osx + +env: + global: + - SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64 + +addons: + apt: + sources: + - debian-sid # Grab shellcheck from the Debian repo (o_O) + packages: + - shellcheck + +install: + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + brew update && brew install openssl; + brew info openssl; + ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; + ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; + ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl; + _old_path="$PATH"; + echo "PATH=$PATH"; + export PATH=""; + export OPENSSL_BIN="/usr/local/openssl"; + openssl version 2>&1 || true; + $OPENSSL_BIN version 2>&1 || true; + export PATH="$_old_path"; + fi + +script: + - echo "TEST_LOCAL=$TEST_LOCAL" + - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" + - which openssl && openssl version + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod +x ~/shfmt ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi + - cd .. + - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest + - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi + + +matrix: + fast_finish: true + + From 5415381cf42f005953392267b75936db5199ddb9 Mon Sep 17 00:00:00 2001 From: Karsten Sperling Date: Fri, 6 Jan 2017 15:27:55 +1300 Subject: [PATCH 062/620] Add support for AWS_SESSION_TOKEN and fix bug when multiple hosted zones exist --- dnsapi/dns_aws.sh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 86d4d044..38b03cd4 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -27,8 +27,10 @@ dns_aws_add() { return 1 fi - _saveaccountconf AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" - _saveaccountconf AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY" + if [ -z "$AWS_SESSION_TOKEN" ]; then + _saveaccountconf AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" + _saveaccountconf AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY" + fi _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -91,7 +93,7 @@ _get_root() { fi if _contains "$response" "$h."; then - hostedzone="$(echo "$response" | sed 's//\n&/g' | _egrep_o ".*$h.<.Name>.*<.HostedZone>")" + hostedzone="$(echo "$response" | sed 's//\n&/g' | _egrep_o ".*?$h.<.Name>.*?<.HostedZone>")" _debug hostedzone "$hostedzone" if [ -z "$hostedzone" ]; then _err "Error, can not get hostedzone." @@ -139,9 +141,13 @@ aws_rest() { aws_host="$AWS_HOST" CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n" - _debug2 CanonicalHeaders "$CanonicalHeaders" - SignedHeaders="host;x-amz-date" + if [ -n "$AWS_SESSION_TOKEN" ]; then + _H2="x-amz-security-token: $AWS_SESSION_TOKEN" + CanonicalHeaders="${CanonicalHeaders}x-amz-security-token:$AWS_SESSION_TOKEN\n" + SignedHeaders="${SignedHeaders};x-amz-security-token" + fi + _debug2 CanonicalHeaders "$CanonicalHeaders" _debug2 SignedHeaders "$SignedHeaders" RequestPayload="$data" From 3cf85634ebb955ecee7616e88f4e1cef4458df41 Mon Sep 17 00:00:00 2001 From: Kevin Kaland Date: Sun, 8 Jan 2017 00:09:21 +0100 Subject: [PATCH 063/620] Trim potential closing curly brace. Fixes GH-517. --- dnsapi/dns_me.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index d7a1b19f..c94a3c90 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -103,7 +103,7 @@ _get_root() { fi if _contains "$response" "\"name\":\"$h\""; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | head -n 1 | cut -d : -f 2) + _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" From 800f02ba381cb526860b12ffdf5c3f9577e93553 Mon Sep 17 00:00:00 2001 From: Bastian Bittorf Date: Mon, 9 Jan 2017 12:19:18 +0100 Subject: [PATCH 064/620] dnsapi/dns_lexicon.sh: shellcheck: fix 4 occurences of SC2021: "Don't use [] around ranges in tr, it replaces literal square brackets." this introduces another warning: "Use '[:lower:]' to support accents and foreign alphabets." This is more a style thingy because we really want to only catch A-Z. work around this by using a shellcheck-directive and a comment that the [:lower:] will not work with e.g. busybox-ash. if we later really want to use [:lower:], we should use 'sed' for that. --- .travis.yml | 2 +- dnsapi/dns_lexicon.sh | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0667919d..fd4ee25c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index 4ab65645..0398bd2e 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -30,7 +30,9 @@ dns_lexicon_add() { _savedomainconf PROVIDER "$PROVIDER" export PROVIDER - Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr '[a-z]' '[A-Z]') + # e.g. busybox-ash does not know [:upper:] + # shellcheck disable=SC2018,SC2019 + Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z') Lx_name_v=$(eval echo \$"$Lx_name") _debug "$Lx_name" "$Lx_name_v" if [ "$Lx_name_v" ]; then @@ -38,7 +40,8 @@ dns_lexicon_add() { eval export "$Lx_name" fi - Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr '[a-z]' '[A-Z]') + # shellcheck disable=SC2018,SC2019 + Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z') Lx_token_v=$(eval echo \$"$Lx_token") _debug "$Lx_token" "$Lx_token_v" if [ "$Lx_token_v" ]; then @@ -46,7 +49,8 @@ dns_lexicon_add() { eval export "$Lx_token" fi - Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr '[a-z]' '[A-Z]') + # shellcheck disable=SC2018,SC2019 + Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z') Lx_password_v=$(eval echo \$"$Lx_password") _debug "$Lx_password" "$Lx_password_v" if [ "$Lx_password_v" ]; then @@ -54,7 +58,8 @@ dns_lexicon_add() { eval export "$Lx_password" fi - Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr '[a-z]' '[A-Z]') + # shellcheck disable=SC2018,SC2019 + Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z') Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken") _debug "$Lx_domaintoken" "$Lx_domaintoken_v" if [ "$Lx_domaintoken_v" ]; then From d11d476126a6958211d9813ebf34c1e33f25055a Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 9 Jan 2017 20:26:07 +0800 Subject: [PATCH 065/620] "Don't use [] around ranges in tr, it replaces literal square brackets." --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 06b14ef6..d0f97b1a 100755 --- a/acme.sh +++ b/acme.sh @@ -573,7 +573,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 671a69947219a745cb3882b33d4b60a312b5cb60 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 9 Jan 2017 22:01:48 +0800 Subject: [PATCH 066/620] minor, fix shellcheck warning --- dnsapi/dns_dp.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 06833b4b..3691be06 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -199,7 +199,7 @@ _get_root() { #Usage: method URI data _rest() { - m=$1 + m="$1" ep="$2" data="$3" _debug "$ep" @@ -207,11 +207,11 @@ _rest() { _debug url "$url" - if [ "$data" ]; then + if [ "$m" = "GET" ]; then + response="$(_get "$url" | tr -d '\r')" + else _debug2 data "$data" response="$(_post "$data" "$url" | tr -d '\r')" - else - response="$(_get "$url" | tr -d '\r')" fi if [ "$?" != "0" ]; then From 3b67cf4378c5dfc141dce4e66639d4fa7d2b462b Mon Sep 17 00:00:00 2001 From: Bastian Bittorf Date: Mon, 9 Jan 2017 15:08:41 +0100 Subject: [PATCH 067/620] dnsapi/dns_dp.sh: shellcheck: fix 1 occurence of SC2126 shellcheck message was: "Consider using grep -c instead of grep | wc" --- .travis.yml | 2 +- dnsapi/dns_dp.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index fd4ee25c..1924f82a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2034 **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi diff --git a/dnsapi/dns_dp.sh b/dnsapi/dns_dp.sh index 3691be06..301a1f6c 100755 --- a/dnsapi/dns_dp.sh +++ b/dnsapi/dns_dp.sh @@ -102,7 +102,7 @@ existing_records() { fi if _contains "$response" "Action completed successful"; then - count=$(printf "%s" "$response" | grep 'TXT' | wc -l | tr -d ' ') + count=$(printf "%s" "$response" | grep -c 'TXT' | tr -d ' ') record_id=$(printf "%s" "$response" | grep '^' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1) _debug record_id "$record_id" return 0 From 5413bf8753bce20471a3023559e176db6e9c1977 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 10 Jan 2017 10:36:47 +0800 Subject: [PATCH 068/620] minor, clear account key cache if new-authz error. --- acme.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/acme.sh b/acme.sh index d0f97b1a..bd3a51b5 100755 --- a/acme.sh +++ b/acme.sh @@ -2356,6 +2356,12 @@ __get_domain_new_authz() { _err "Can not get domain new authz." return 1 fi + if _contains "$response" "No registration exists matching provided key"; then + _err "It seems there is an error, but it's recovered now, please try again." + _err "If you see this message for a second time, please report bug: $(__green "$PROJECT")" + _clearcaconf "CA_KEY_HASH" + break + fi if ! _contains "$response" "An error occurred while processing your request"; then _info "The new-authz request is ok." break From 1699e94f0ffdd056cd58891dd43a4386b2246471 Mon Sep 17 00:00:00 2001 From: Geoffroi Date: Wed, 11 Jan 2017 14:09:58 +0100 Subject: [PATCH 069/620] Adding kong deploy script (https://getkong.org) --- deploy/kong.sh | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 deploy/kong.sh diff --git a/deploy/kong.sh b/deploy/kong.sh new file mode 100644 index 00000000..cd9de10c --- /dev/null +++ b/deploy/kong.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env sh + +# This deploy hook will deploy ssl cert on kong proxy engine based on api request_host parameter. +# Note that ssl plugin should be available on Kong instance +# The hook will match cdomain to request_host, in case of multiple domain it will always take the first +# one (acme.sh behaviour). +# If ssl config already exist it will update only cert and key not touching other parameter +# If ssl config doesn't exist it will only upload cert and key and not set other parameter +# Not that we deploy full chain +# See https://getkong.org/plugins/dynamic-ssl/ for other options +# Written by Geoffroi Genot + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +kong.sh_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + _info "Deploying certificate on Kong instance" + if [ -z "$KONG_URL" ] + then + _debug "KONG_URL Not set, using default http://localhost:8001" + KONG_URL="http://localhost:8001" + fi + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + #Get uuid linked to the domain + uuid=$( _get "$KONG_URL/apis?request_host=$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' ) + if [ "$uuid" = "" ] + then + _err "Unable to get Kong uuid for domain $_cdomain" + _err "Make sure that KONG_URL is correctly configured" + _err "Make sure that a Kong api request_host match the domain" + _err "Kong url: $KONG_URL" + return 1 + fi + #Save kong url if it's succesful (First run case) + _saveaccountconf KONG_URL "$KONG_URL" + #Generate DEIM + delim="-----MultipartDelimeter$(date "+%s%N")" + nl=$( printf "\\r\\n" ) + #Set Header + _H1="Content-Type: multipart/form-data; boundary=$delim" + #Generate data for request (Multipart/form-data with mixed content) + #set name to ssl + content="--$delim${nl}Content-Disposition: form-data; name=\"name\"${nl}${nl}ssl" + #add key + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"config.key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" + #Add cert + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"config.cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")" + #Close multipart + content="$content${nl}--$delim--${nl}" + #DEBUG + _debug header "$_H1" + _debug content "$content" + #Check if ssl plugins is aready enabled (if not => POST else => PATCH) + ssl_uuid=$(_get $KONG_URL/apis/$uuid/plugins | _egrep_o '"id":"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"[a-zA-Z0-9\-\,\"_\:]*"name":"ssl"' | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' ) + _debug ssl_uuid "$ssl_uuid" + if [ "$ssl_uuid" = "" ] + then + #Post certificate to Kong + response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST" ) + else + #patch + response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH" ) + fi + if ! [ "$( echo "$response" | _egrep_o "ssl" )" = "ssl" ] + then + _err "An error occured with cert upload. Check response:" + _err "$response" + return 1 + fi + _debug response "$response" + _info "Certificate successfully deployed" +} From 07feb87deeab89fe55af42a532b463f1e3cc3ae8 Mon Sep 17 00:00:00 2001 From: Geoffroi Date: Wed, 11 Jan 2017 14:52:52 +0100 Subject: [PATCH 070/620] Travis fix --- deploy/kong.sh | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index cd9de10c..0fa726a3 100644 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -20,8 +20,7 @@ kong.sh_deploy() { _cca="$4" _cfullchain="$5" _info "Deploying certificate on Kong instance" - if [ -z "$KONG_URL" ] - then + if [ -z "$KONG_URL" ]; then _debug "KONG_URL Not set, using default http://localhost:8001" KONG_URL="http://localhost:8001" fi @@ -33,9 +32,8 @@ kong.sh_deploy() { _debug _cfullchain "$_cfullchain" #Get uuid linked to the domain - uuid=$( _get "$KONG_URL/apis?request_host=$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' ) - if [ "$uuid" = "" ] - then + uuid=$( _get "$KONG_URL/apis?request_host=$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') + if [ "$uuid" = "" ]; then _err "Unable to get Kong uuid for domain $_cdomain" _err "Make sure that KONG_URL is correctly configured" _err "Make sure that a Kong api request_host match the domain" @@ -46,7 +44,7 @@ kong.sh_deploy() { _saveaccountconf KONG_URL "$KONG_URL" #Generate DEIM delim="-----MultipartDelimeter$(date "+%s%N")" - nl=$( printf "\\r\\n" ) + nl=$(printf "\\r\\n") #Set Header _H1="Content-Type: multipart/form-data; boundary=$delim" #Generate data for request (Multipart/form-data with mixed content) @@ -62,18 +60,17 @@ kong.sh_deploy() { _debug header "$_H1" _debug content "$content" #Check if ssl plugins is aready enabled (if not => POST else => PATCH) - ssl_uuid=$(_get $KONG_URL/apis/$uuid/plugins | _egrep_o '"id":"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"[a-zA-Z0-9\-\,\"_\:]*"name":"ssl"' | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' ) + ssl_uuid=$(_get "$KONG_URL/apis/$uuid/plugins" | _egrep_o '"id":"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"[a-zA-Z0-9\-\,\"_\:]*"name":"ssl"' | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') _debug ssl_uuid "$ssl_uuid" if [ "$ssl_uuid" = "" ] then #Post certificate to Kong - response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST" ) + response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST") else #patch - response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH" ) + response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH") fi - if ! [ "$( echo "$response" | _egrep_o "ssl" )" = "ssl" ] - then + if ! [ "$( echo "$response" | _egrep_o "ssl" )" = "ssl" ]; then _err "An error occured with cert upload. Check response:" _err "$response" return 1 From e2cc350fbc90c18e5574361d15ce57f600eaa42c Mon Sep 17 00:00:00 2001 From: Geoffroi Date: Wed, 11 Jan 2017 14:54:52 +0100 Subject: [PATCH 071/620] Fix function name --- deploy/kong.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 0fa726a3..86a1835b 100644 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -13,7 +13,7 @@ ######## Public functions ##################### #domain keyfile certfile cafile fullchain -kong.sh_deploy() { +kong_deploy() { _cdomain="$1" _ckey="$2" _ccert="$3" From 753d0e7df77b9dcf261da4547c679fec49df0961 Mon Sep 17 00:00:00 2001 From: Geoffroi Date: Wed, 11 Jan 2017 15:05:26 +0100 Subject: [PATCH 072/620] Syntax fix part 2 --- deploy/kong.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 86a1835b..2eab3d4e 100644 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -21,8 +21,8 @@ kong_deploy() { _cfullchain="$5" _info "Deploying certificate on Kong instance" if [ -z "$KONG_URL" ]; then - _debug "KONG_URL Not set, using default http://localhost:8001" - KONG_URL="http://localhost:8001" + _debug "KONG_URL Not set, using default http://localhost:8001" + KONG_URL="http://localhost:8001" fi _debug _cdomain "$_cdomain" @@ -32,7 +32,7 @@ kong_deploy() { _debug _cfullchain "$_cfullchain" #Get uuid linked to the domain - uuid=$( _get "$KONG_URL/apis?request_host=$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') + uuid=$(_get "$KONG_URL/apis?request_host=$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') if [ "$uuid" = "" ]; then _err "Unable to get Kong uuid for domain $_cdomain" _err "Make sure that KONG_URL is correctly configured" @@ -62,15 +62,14 @@ kong_deploy() { #Check if ssl plugins is aready enabled (if not => POST else => PATCH) ssl_uuid=$(_get "$KONG_URL/apis/$uuid/plugins" | _egrep_o '"id":"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"[a-zA-Z0-9\-\,\"_\:]*"name":"ssl"' | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') _debug ssl_uuid "$ssl_uuid" - if [ "$ssl_uuid" = "" ] - then + if [ "$ssl_uuid" = "" ]; then #Post certificate to Kong response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST") else #patch response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH") fi - if ! [ "$( echo "$response" | _egrep_o "ssl" )" = "ssl" ]; then + if ! [ "$(echo "$response" | _egrep_o "ssl")" = "ssl" ]; then _err "An error occured with cert upload. Check response:" _err "$response" return 1 From 5fe91d65770d84e6de633384f94fcdcd5a9e6039 Mon Sep 17 00:00:00 2001 From: Geoffroi Date: Wed, 11 Jan 2017 16:17:16 +0100 Subject: [PATCH 073/620] Correction of test from comment of Neilpang + Correction of CRLF with sh not working correctly --- deploy/kong.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 2eab3d4e..3b9c5c79 100644 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -33,7 +33,7 @@ kong_deploy() { #Get uuid linked to the domain uuid=$(_get "$KONG_URL/apis?request_host=$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') - if [ "$uuid" = "" ]; then + if [ -z "$uuid" ]; then _err "Unable to get Kong uuid for domain $_cdomain" _err "Make sure that KONG_URL is correctly configured" _err "Make sure that a Kong api request_host match the domain" @@ -44,7 +44,7 @@ kong_deploy() { _saveaccountconf KONG_URL "$KONG_URL" #Generate DEIM delim="-----MultipartDelimeter$(date "+%s%N")" - nl=$(printf "\\r\\n") + nl="\015\012" #Set Header _H1="Content-Type: multipart/form-data; boundary=$delim" #Generate data for request (Multipart/form-data with mixed content) @@ -56,13 +56,15 @@ kong_deploy() { content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"config.cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")" #Close multipart content="$content${nl}--$delim--${nl}" + #Convert CRLF + content=$(printf %b "$content") #DEBUG _debug header "$_H1" _debug content "$content" #Check if ssl plugins is aready enabled (if not => POST else => PATCH) ssl_uuid=$(_get "$KONG_URL/apis/$uuid/plugins" | _egrep_o '"id":"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"[a-zA-Z0-9\-\,\"_\:]*"name":"ssl"' | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') _debug ssl_uuid "$ssl_uuid" - if [ "$ssl_uuid" = "" ]; then + if [ -z "$ssl_uuid" ]; then #Post certificate to Kong response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST") else From 2fbf39915652975f0b15a4090919ac22ccc5c374 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 13 Jan 2017 20:49:58 +0800 Subject: [PATCH 074/620] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index bd3a51b5..6eace3fd 100755 --- a/acme.sh +++ b/acme.sh @@ -4540,7 +4540,7 @@ _process() { if [ "$INSTALLONLINE" ]; then INSTALLONLINE="" - _installOnline $BRANCH + _installOnline exit fi From 3ca93f4a4c679b93361f3ae411fd0eceda813f3c Mon Sep 17 00:00:00 2001 From: Bastian Bittorf Date: Mon, 9 Jan 2017 17:04:09 +0100 Subject: [PATCH 075/620] shellcheck: fix several occurences of SC2034 message: SC2034: $VARNAME appears unused. Verify it or export it. most of these are related to the style: we generate global vars, which are used in other functions. the var "lexical_url" was really unused (left it as comment) the travis-check now does not need anymore special flags. Signed-off-by: Bastian Bittorf --- .travis.yml | 2 +- dnsapi/dns_ad.sh | 4 ++-- dnsapi/dns_aws.sh | 4 ++-- dnsapi/dns_cf.sh | 6 +++--- dnsapi/dns_cx.sh | 8 ++++---- dnsapi/dns_gd.sh | 4 ++-- dnsapi/dns_ispconfig.sh | 2 +- dnsapi/dns_lexicon.sh | 2 +- dnsapi/dns_lua.sh | 4 ++-- dnsapi/dns_me.sh | 6 +++--- dnsapi/dns_ovh.sh | 10 +++++----- dnsapi/dns_pdns.sh | 2 +- 12 files changed, 27 insertions(+), 27 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1924f82a..1fff02e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2034 **/*.sh && echo "shellcheck OK" ; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index 1c7e85f9..fc4a664b 100644 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -127,8 +127,8 @@ _ad_rest() { _debug mtd "$mtd" _debug ep "$ep" - _H1="Accept: application/json" - _H2="Content-Type: application/json" + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" if [ "$mtd" != "GET" ]; then # both POST and DELETE. diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 38b03cd4..59ef6181 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -137,13 +137,13 @@ aws_rest() { #RequestDate="20161120T141056Z" ############## - _H1="x-amz-date: $RequestDate" + export _H1="x-amz-date: $RequestDate" aws_host="$AWS_HOST" CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n" SignedHeaders="host;x-amz-date" if [ -n "$AWS_SESSION_TOKEN" ]; then - _H2="x-amz-security-token: $AWS_SESSION_TOKEN" + export _H2="x-amz-security-token: $AWS_SESSION_TOKEN" CanonicalHeaders="${CanonicalHeaders}x-amz-security-token:$AWS_SESSION_TOKEN\n" SignedHeaders="${SignedHeaders};x-amz-security-token" fi diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 0b817d36..3718f9db 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -163,9 +163,9 @@ _cf_rest() { data="$3" _debug "$ep" - _H1="X-Auth-Email: $CF_Email" - _H2="X-Auth-Key: $CF_Key" - _H3="Content-Type: application/json" + export _H1="X-Auth-Email: $CF_Email" + export _H2="X-Auth-Key: $CF_Key" + export _H3="Content-Type: application/json" if [ "$m" != "GET" ]; then _debug data "$data" diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index dfc838ae..9c032fd7 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -193,10 +193,10 @@ _rest() { hmac=$(printf "%s" "$sec" | _digest md5 hex) _debug hmac "$hmac" - _H1="API-KEY: $CX_Key" - _H2="API-REQUEST-DATE: $cdate" - _H3="API-HMAC: $hmac" - _H4="Content-Type: application/json" + export _H1="API-KEY: $CX_Key" + export _H2="API-REQUEST-DATE: $cdate" + export _H3="API-HMAC: $hmac" + export _H4="Content-Type: application/json" if [ "$data" ]; then response="$(_post "$data" "$url" "" "$m")" diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 81000561..1abeeacf 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -98,8 +98,8 @@ _gd_rest() { data="$3" _debug "$ep" - _H1="Authorization: sso-key $GD_Key:$GD_Secret" - _H2="Content-Type: application/json" + export _H1="Authorization: sso-key $GD_Key:$GD_Secret" + export _H2="Content-Type: application/json" if [ "$data" ]; then _debug data "$data" diff --git a/dnsapi/dns_ispconfig.sh b/dnsapi/dns_ispconfig.sh index a84d95d7..6d1f34c5 100755 --- a/dnsapi/dns_ispconfig.sh +++ b/dnsapi/dns_ispconfig.sh @@ -46,7 +46,7 @@ _ISPC_credentials() { _saveaccountconf ISPC_Api "${ISPC_Api}" _saveaccountconf ISPC_Api_Insecure "${ISPC_Api_Insecure}" # Set whether curl should use secure or insecure mode - HTTPS_INSECURE="${ISPC_Api_Insecure}" + export HTTPS_INSECURE="${ISPC_Api_Insecure}" fi } diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index 0398bd2e..c38ff3e3 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -2,7 +2,7 @@ # dns api wrapper of lexicon for acme.sh -lexicon_url="https://github.com/AnalogJ/lexicon" +# https://github.com/AnalogJ/lexicon lexicon_cmd="lexicon" wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api" diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index bc06b3ef..47f4497a 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -125,8 +125,8 @@ _LUA_rest() { data="$3" _debug "$ep" - _H1="Accept: application/json" - _H2="Authorization: Basic $LUA_auth" + export _H1="Accept: application/json" + export _H2="Authorization: Basic $LUA_auth" if [ "$data" ]; then _debug data "$data" response="$(_post "$data" "$LUA_Api/$ep" "" "$m")" diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index c94a3c90..9fe6baf8 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -126,9 +126,9 @@ _me_rest() { cdate=$(date -u +"%a, %d %b %Y %T %Z") hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(_hex "$ME_Secret")" hex) - _H1="x-dnsme-apiKey: $ME_Key" - _H2="x-dnsme-requestDate: $cdate" - _H3="x-dnsme-hmac: $hmac" + export _H1="x-dnsme-apiKey: $ME_Key" + export _H2="x-dnsme-requestDate: $cdate" + export _H3="x-dnsme-hmac: $hmac" if [ "$data" ]; then _debug data "$data" diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 18b9c341..8833c0a1 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -273,12 +273,12 @@ _ovh_rest() { _ovh_hex="$(printf "%s" "$_ovh_p" | _digest sha1 hex)" _debug2 _ovh_hex "$_ovh_hex" - _H1="X-Ovh-Application: $OVH_AK" - _H2="X-Ovh-Signature: \$1\$$_ovh_hex" + export _H1="X-Ovh-Application: $OVH_AK" + export _H2="X-Ovh-Signature: \$1\$$_ovh_hex" _debug2 _H2 "$_H2" - _H3="X-Ovh-Timestamp: $_ovh_t" - _H4="X-Ovh-Consumer: $OVH_CK" - _H5="Content-Type: application/json;charset=utf-8" + export _H3="X-Ovh-Timestamp: $_ovh_t" + export _H4="X-Ovh-Consumer: $OVH_CK" + export _H5="Content-Type: application/json;charset=utf-8" if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ]; then _debug data "$data" response="$(_post "$data" "$_ovh_url" "" "$m")" diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index 06763d88..ebc02949 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -165,7 +165,7 @@ _pdns_rest() { ep=$2 data=$3 - _H1="X-API-Key: $PDNS_Token" + export _H1="X-API-Key: $PDNS_Token" if [ ! "$method" = "GET" ]; then _debug data "$data" From 2f4b84c0743cb81d2a2f5a868da9e237777d7022 Mon Sep 17 00:00:00 2001 From: Bastian Bittorf Date: Fri, 13 Jan 2017 15:31:10 +0100 Subject: [PATCH 076/620] travis: use only POSIX constructs here, avoid bashisms e.g. [[ ]] -> [ ] and 'which' -> command -V Although this is not strictly needed, it keeps the project uniformly POSIX. Signed-off-by: Bastian Bittorf --- .travis.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1fff02e5..8d6d30ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ addons: - shellcheck install: - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then brew update && brew install openssl; brew info openssl; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; @@ -35,17 +35,17 @@ install: script: - echo "TEST_LOCAL=$TEST_LOCAL" - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - - which openssl && openssl version - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod +x ~/shfmt ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck **/*.sh && echo "shellcheck OK" ; fi + - command -V openssl && openssl version + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then chmod +x ~/shfmt ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then ~/shfmt -l -w -i 2 . ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - - if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi + - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi matrix: From 38f2334360301396cd2baa6dd3eb899fd01cb00a Mon Sep 17 00:00:00 2001 From: Philipp Grosswiler Date: Mon, 16 Jan 2017 15:42:17 +0700 Subject: [PATCH 077/620] Added support for Linode DNS API. --- README.md | 1 + dnsapi/README.md | 19 ++++++++++++++ dnsapi/dns_linode.sh | 60 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100755 dnsapi/dns_linode.sh diff --git a/README.md b/README.md index 9b5891c9..ea0e0de7 100644 --- a/README.md +++ b/README.md @@ -266,6 +266,7 @@ You don't have to do anything manually! 1. aliyun.com(阿里云) API 1. ISPConfig 3.1 API 1. Alwaysdata.com API +1. Linode.com API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index e32b4655..1895d376 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -257,6 +257,25 @@ acme.sh --issue --dns dns_ad -d example.com -d www.example.com The `AD_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 14. Use Linode domain API + +You will need to install the Linode CLI and set it up accordingly. + +[https://www.linode.com/docs/platform/linode-cli](https://www.linode.com/docs/platform/linode-cli) + +Follow the installation instructions appropriate for your platform and then run the configuration. + +```linode configure +``` + +Make sure Linode CLI is working correctly before proceeding. + +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. + +```sh +acme.sh --issue --dns dns_linode --dnssleep 900 -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_linode.sh b/dnsapi/dns_linode.sh new file mode 100755 index 00000000..0af1ad7c --- /dev/null +++ b/dnsapi/dns_linode.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash + +linode_cmd="/usr/bin/linode" + +######## Public functions ##################### + +#Usage: dns_linode_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_linode_add() { + fulldomain="${1}" + txtvalue="${2}" + + _info "Using Linode" + _debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'" + + domain=$(printf "%s" "${fulldomain}" | cut -d . -f 3-999) + name=$(printf "%s" "${fulldomain}" | cut -d . -f 1-2) + _debug name "${name}" + _debug domain "${domain}" + + _Linode_CLI && _Linode_addTXT +} + +#Usage: dns_linode_rm _acme-challenge.www.domain.com +dns_linode_rm() { + fulldomain="${1}" + + _info "Using Linode" + _debug "Calling: dns_linode_rm() '${fulldomain}'" + + domain=$(printf "%s" "${fulldomain}" | cut -d . -f 3-999) + name=$(printf "%s" "${fulldomain}" | cut -d . -f 1-2) + _debug name "${name}" + _debug domain "${domain}" + + _Linode_CLI && _Linode_rmTXT +} + +#################### Private functions below ################################## + +_Linode_CLI() { + if [ ! -f "${linode_cmd}" ]; then + _err "Please install the Linode CLI package and set it up accordingly before using this DNS API." + return 1 + fi +} + +_Linode_addTXT() { + _debug "$linode_cmd domain record-update ${domain} TXT ${name} --target ${txtvalue}" + $linode_cmd domain record-update ${domain} TXT ${name} --target ${txtvalue} + + if [ $? -ne 0 ]; then + _debug "$linode_cmd domain record-create ${domain} TXT ${name} ${txtvalue}" + $linode_cmd domain record-create ${domain} TXT ${name} ${txtvalue} + fi +} + +_Linode_rmTXT() { + _debug "$linode_cmd domain record-delete ${domain} TXT ${name}" + $linode_cmd domain record-delete ${domain} TXT ${name} +} From 27dbe77fad0e59ad9bce55df8d165ca512be0c65 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 16 Jan 2017 22:31:24 +0800 Subject: [PATCH 078/620] add "--config-home" --- acme.sh | 110 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 74 insertions(+), 36 deletions(-) diff --git a/acme.sh b/acme.sh index 6eace3fd..0cbae7ba 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.5 +VER=2.6.6 PROJECT_NAME="acme.sh" @@ -1634,7 +1634,11 @@ __initHome() { fi export LE_WORKING_DIR - _DEFAULT_ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf" + if [ -z "$CONFIG_HOME" ]; then + CONFIG_HOME="$LE_WORKING_DIR" + fi + + _DEFAULT_ACCOUNT_CONF_PATH="$CONFIG_HOME/account.conf" if [ -z "$ACCOUNT_CONF_PATH" ]; then if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]; then @@ -1646,12 +1650,12 @@ __initHome() { ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH" fi - DEFAULT_LOG_FILE="$LE_WORKING_DIR/$PROJECT_NAME.log" + DEFAULT_LOG_FILE="$CONFIG_HOME/$PROJECT_NAME.log" - DEFAULT_CA_HOME="$LE_WORKING_DIR/ca" + DEFAULT_CA_HOME="$CONFIG_HOME/ca" if [ -z "$LE_TEMP_DIR" ]; then - LE_TEMP_DIR="$LE_WORKING_DIR/tmp" + LE_TEMP_DIR="$CONFIG_HOME/tmp" fi } @@ -1703,7 +1707,7 @@ _initpath() { fi if [ -z "$APACHE_CONF_BACKUP_DIR" ]; then - APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR" + APACHE_CONF_BACKUP_DIR="$CONFIG_HOME" fi if [ -z "$USER_AGENT" ]; then @@ -1711,7 +1715,7 @@ _initpath() { fi if [ -z "$HTTP_HEADER" ]; then - HTTP_HEADER="$LE_WORKING_DIR/http.header" + HTTP_HEADER="$CONFIG_HOME/http.header" fi _OLD_ACCOUNT_KEY="$LE_WORKING_DIR/account.key" @@ -1727,7 +1731,7 @@ _initpath() { ACCOUNT_JSON_PATH="$_DEFAULT_ACCOUNT_JSON_PATH" fi - _DEFAULT_CERT_HOME="$LE_WORKING_DIR" + _DEFAULT_CERT_HOME="$CONFIG_HOME" if [ -z "$CERT_HOME" ]; then CERT_HOME="$_DEFAULT_CERT_HOME" fi @@ -3350,7 +3354,9 @@ _installcert() { } +#confighome installcronjob() { + _c_home="$1" _initpath if ! _exists "crontab"; then _err "crontab doesn't exist, so, we can not install cron jobs." @@ -3367,15 +3373,20 @@ installcronjob() { _err "Can not install cronjob, $PROJECT_ENTRY not found." return 1 fi + + if [ "$_c_home" ]; then + _c_entry="--config-home \"$_c_home\"" + fi + if _exists uname && uname -a | grep SunOS >/dev/null; then crontab -l | { cat - echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" + echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry > /dev/null" } | crontab -- else crontab -l | { cat - echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" + echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry > /dev/null" } | crontab - fi fi @@ -3401,6 +3412,10 @@ uninstallcronjob() { fi LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')" _info LE_WORKING_DIR "$LE_WORKING_DIR" + if _contains "$cr" "--config-home"; then + CONFIG_HOME="$(echo "$cr" | cut -d ' ' -f 11 | tr -d '"')" + _debug CONFIG_HOME "$CONFIG_HOME" + fi fi _initpath @@ -3664,7 +3679,9 @@ _setShebang() { rm -f "$_file.tmp" } +#confighome _installalias() { + _c_home="$1" _initpath _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env" @@ -3674,8 +3691,12 @@ _installalias() { echo "$(cat "$_envfile")" | sed "s|^alias le.sh.*$||" >"$_envfile" fi + if [ "$_c_home" ]; then + _c_entry="--config-home '$_c_home'" + fi + _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" - _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" + _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" _profile="$(_detect_profile)" if [ "$_profile" ]; then @@ -3693,7 +3714,7 @@ _installalias() { if [ -f "$_csh_profile" ]; then _info "Installing alias to '$_csh_profile'" _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" - _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" + _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" _setopt "$_csh_profile" "source \"$_cshfile\"" fi @@ -3702,13 +3723,13 @@ _installalias() { if [ -f "$_tcsh_profile" ]; then _info "Installing alias to '$_tcsh_profile'" _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" - _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\"" + _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" _setopt "$_tcsh_profile" "source \"$_cshfile\"" fi } -# nocron +# nocron confighome install() { if [ -z "$LE_WORKING_DIR" ]; then @@ -3716,6 +3737,7 @@ install() { fi _nocron="$1" + _c_home="$2" if ! _initpath; then _err "Install failed." return 1 @@ -3754,6 +3776,13 @@ install() { chmod 700 "$LE_WORKING_DIR" + if ! mkdir -p "$CONFIG_HOME"; then + _err "Can not create config dir: $CONFIG_HOME" + return 1 + fi + + chmod 700 "$CONFIG_HOME" + cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" if [ "$?" != "0" ]; then @@ -3763,7 +3792,7 @@ install() { _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY" - _installalias + _installalias "$_c_home" for subf in $_SUB_FOLDERS; do if [ -d "$subf" ]; then @@ -3789,7 +3818,7 @@ install() { fi if [ -z "$_nocron" ]; then - installcronjob + installcronjob "$_c_home" fi if [ -z "$NO_DETECT_SH" ]; then @@ -3822,7 +3851,7 @@ uninstall() { _uninstallalias rm -f "$LE_WORKING_DIR/$PROJECT_ENTRY" - _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself." + _info "The keys and certs are in \"$(__green "$CONFIG_HOME")\", you can remove them by yourself." } @@ -3895,18 +3924,18 @@ Commands: --issue Issue a cert. --signcsr Issue a cert from an existing csr. --deploy Deploy the cert to your server. - --installcert Install the issued cert to apache/nginx or any other server. + --install-cert Install the issued cert to apache/nginx or any other server. --renew, -r Renew a cert. - --renewAll Renew all the certs. + --renew-all Renew all the certs. --revoke Revoke a cert. --list List all the certs. --showcsr Show the content of a csr. - --installcronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. - --uninstallcronjob Uninstall the cron job. The 'uninstall' command can do this automatically. + --install-cronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. + --uninstall-cronjob Uninstall the cron job. The 'uninstall' command can do this automatically. --cron Run cron job to renew all the certs. --toPkcs Export the certificate and key to a pfx file. - --updateaccount Update account info. - --registeraccount Register account key. + --update-account Update account info. + --register-account Register account key. --createAccountKey, -cak Create an account private key, professional use. --createDomainKey, -cdk Create an domain private key, professional use. --createCSR, -ccsr Create CSR , professional use. @@ -3941,7 +3970,8 @@ Parameters: --accountconf Specifies a customized account config file. --home Specifies the home dir for $PROJECT_NAME . - --certhome Specifies the home dir to save all the certs, only valid for '--install' command. + --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. --accountemail Specifies the account email for registering, Only valid for the '--install' command. --accountkey Specifies the account key path, Only valid for the '--install' command. @@ -3950,11 +3980,11 @@ Parameters: --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 '--renewall' command. Stop if one cert has error in renewal. + --stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal. --insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted. --ca-bundle Specifices the path to the CA certificate bundle to verify api server's certificate. --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. - --ecc Specifies to use the ECC cert. Valid for '--installcert', '--renew', '--revoke', '--toPkcs' and '--createCSR' + --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' --csr Specifies the input csr. --pre-hook Command to be run before obtaining any certificates. --post-hook Command to be run after attempting to obtain/renew certificates. No matter the obain/renew is success or failed. @@ -4063,6 +4093,7 @@ _process() { _accountemail="" _accountkey="" _certhome="" + _confighome="" _httpport="" _tlsport="" _dnssleep="" @@ -4117,13 +4148,13 @@ _process() { --showcsr) _CMD="showcsr" ;; - --installcert | -i) + --installcert | -i|--install-cert) _CMD="installcert" ;; --renew | -r) _CMD="renew" ;; - --renewAll | --renewall) + --renewAll | --renewall|--renew-all) _CMD="renewAll" ;; --revoke) @@ -4132,10 +4163,10 @@ _process() { --list) _CMD="list" ;; - --installcronjob) + --installcronjob|--install-cronjob) _CMD="installcronjob" ;; - --uninstallcronjob) + --uninstallcronjob|--install-cronjob) _CMD="uninstallcronjob" ;; --cron) @@ -4156,10 +4187,10 @@ _process() { --deactivate) _CMD="deactivate" ;; - --updateaccount) + --updateaccount|--update-account) _CMD="updateaccount" ;; - --registeraccount) + --registeraccount|--register-account) _CMD="registeraccount" ;; --domain | -d) @@ -4301,11 +4332,16 @@ _process() { LE_WORKING_DIR="$2" shift ;; - --certhome) + --certhome|--cert-home) _certhome="$2" CERT_HOME="$_certhome" shift ;; + --config-home) + _confighome="$2" + CONFIG_HOME="$_confighome" + shift + ;; --useragent) _useragent="$2" USER_AGENT="$_useragent" @@ -4456,7 +4492,7 @@ _process() { fi case "${_CMD}" in - install) install "$_nocron" ;; + install) install "$_nocron" "$_confighome" ;; uninstall) uninstall "$_nocron" ;; upgrade) upgrade ;; issue) @@ -4495,7 +4531,7 @@ _process() { list) list "$_listraw" ;; - installcronjob) installcronjob ;; + installcronjob) installcronjob "$_confighome" ;; uninstallcronjob) uninstallcronjob ;; cron) cron ;; toPkcs) @@ -4512,7 +4548,9 @@ _process() { ;; *) - _err "Invalid command: $_CMD" + if [ "$_CMD" ]; then + _err "Invalid command: $_CMD" + fi showhelp return 1 ;; From 80941f84137c45014da23d7e3db17e3d267305c9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 16 Jan 2017 22:36:13 +0800 Subject: [PATCH 079/620] minor --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 0cbae7ba..07500eed 100755 --- a/acme.sh +++ b/acme.sh @@ -3375,18 +3375,18 @@ installcronjob() { fi if [ "$_c_home" ]; then - _c_entry="--config-home \"$_c_home\"" + _c_entry="--config-home \"$_c_home\" " fi if _exists uname && uname -a | grep SunOS >/dev/null; then crontab -l | { cat - echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry > /dev/null" + echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null" } | crontab -- else crontab -l | { cat - echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry > /dev/null" + echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null" } | crontab - fi fi From ee20015d4460b2b9bd5647f9e3d4e5f9bd1dbc6d Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 17 Jan 2017 13:04:02 +0800 Subject: [PATCH 080/620] fix format --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 07500eed..b58a3f47 100755 --- a/acme.sh +++ b/acme.sh @@ -4148,7 +4148,7 @@ _process() { --showcsr) _CMD="showcsr" ;; - --installcert | -i|--install-cert) + --installcert | -i| --install-cert) _CMD="installcert" ;; --renew | -r) @@ -4163,10 +4163,10 @@ _process() { --list) _CMD="list" ;; - --installcronjob|--install-cronjob) + --installcronjob | --install-cronjob) _CMD="installcronjob" ;; - --uninstallcronjob|--install-cronjob) + --uninstallcronjob|--uninstall-cronjob) _CMD="uninstallcronjob" ;; --cron) @@ -4187,10 +4187,10 @@ _process() { --deactivate) _CMD="deactivate" ;; - --updateaccount|--update-account) + --updateaccount | --update-account) _CMD="updateaccount" ;; - --registeraccount|--register-account) + --registeraccount | --register-account) _CMD="registeraccount" ;; --domain | -d) @@ -4332,7 +4332,7 @@ _process() { LE_WORKING_DIR="$2" shift ;; - --certhome|--cert-home) + --certhome | --cert-home) _certhome="$2" CERT_HOME="$_certhome" shift From db7e4bf9405c55e2361a8f2140c60b092c6c1d3c Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 17 Jan 2017 13:06:44 +0800 Subject: [PATCH 081/620] fix format --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index b58a3f47..c24b019d 100755 --- a/acme.sh +++ b/acme.sh @@ -4148,13 +4148,13 @@ _process() { --showcsr) _CMD="showcsr" ;; - --installcert | -i| --install-cert) + --installcert | -i | --install-cert) _CMD="installcert" ;; --renew | -r) _CMD="renew" ;; - --renewAll | --renewall|--renew-all) + --renewAll | --renewall | --renew-all) _CMD="renewAll" ;; --revoke) @@ -4166,7 +4166,7 @@ _process() { --installcronjob | --install-cronjob) _CMD="installcronjob" ;; - --uninstallcronjob|--uninstall-cronjob) + --uninstallcronjob | --uninstall-cronjob) _CMD="uninstallcronjob" ;; --cron) From 2aff36e74b4cf406bbd74ecf80dca64a0aef8d10 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 17 Jan 2017 20:13:15 +0800 Subject: [PATCH 082/620] fix comma in domain --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index 6eace3fd..66abd882 100755 --- a/acme.sh +++ b/acme.sh @@ -2391,6 +2391,10 @@ issue() { Le_Webroot="$1" Le_Domain="$2" Le_Alt="$3" + if _contains "$Le_Domain" ","; then + Le_Domain=$(echo "$2,$3" | cut -d , -f 1) + Le_Alt=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") + fi Le_Keylength="$4" Le_RealCertPath="$5" Le_RealKeyPath="$6" From 32b3717c32196dea163e87b40d428774fded5c25 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 17 Jan 2017 21:49:02 +0800 Subject: [PATCH 083/620] random minute --- acme.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 66abd882..49f3c3fd 100755 --- a/acme.sh +++ b/acme.sh @@ -3371,15 +3371,18 @@ installcronjob() { _err "Can not install cronjob, $PROJECT_ENTRY not found." return 1 fi + + _t=$(_time) + random_minute=$(_math $_t % 60) if _exists uname && uname -a | grep SunOS >/dev/null; then crontab -l | { cat - echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" + echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" } | crontab -- else crontab -l | { cat - echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" + echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" } | crontab - fi fi From 0f21537f148e0522d305713b66677de387d95b28 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 17 Jan 2017 22:01:36 +0800 Subject: [PATCH 084/620] format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 49f3c3fd..0ee1eeee 100755 --- a/acme.sh +++ b/acme.sh @@ -3371,7 +3371,7 @@ installcronjob() { _err "Can not install cronjob, $PROJECT_ENTRY not found." return 1 fi - + _t=$(_time) random_minute=$(_math $_t % 60) if _exists uname && uname -a | grep SunOS >/dev/null; then From f5b546b3c8c437b2e43406ac15df575e34210a9b Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 21 Jan 2017 11:28:10 +0800 Subject: [PATCH 085/620] rename to LE_CONFIG_HOME --- acme.sh | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/acme.sh b/acme.sh index b9da2f46..33fd6201 100755 --- a/acme.sh +++ b/acme.sh @@ -1634,11 +1634,13 @@ __initHome() { fi export LE_WORKING_DIR - if [ -z "$CONFIG_HOME" ]; then - CONFIG_HOME="$LE_WORKING_DIR" + if [ -z "$LE_CONFIG_HOME" ]; then + LE_CONFIG_HOME="$LE_WORKING_DIR" fi + _debug "Using config home:$LE_CONFIG_HOME" + export LE_CONFIG_HOME - _DEFAULT_ACCOUNT_CONF_PATH="$CONFIG_HOME/account.conf" + _DEFAULT_ACCOUNT_CONF_PATH="$LE_CONFIG_HOME/account.conf" if [ -z "$ACCOUNT_CONF_PATH" ]; then if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]; then @@ -1650,12 +1652,12 @@ __initHome() { ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH" fi - DEFAULT_LOG_FILE="$CONFIG_HOME/$PROJECT_NAME.log" + DEFAULT_LOG_FILE="$LE_CONFIG_HOME/$PROJECT_NAME.log" - DEFAULT_CA_HOME="$CONFIG_HOME/ca" + DEFAULT_CA_HOME="$LE_CONFIG_HOME/ca" if [ -z "$LE_TEMP_DIR" ]; then - LE_TEMP_DIR="$CONFIG_HOME/tmp" + LE_TEMP_DIR="$LE_CONFIG_HOME/tmp" fi } @@ -1707,7 +1709,7 @@ _initpath() { fi if [ -z "$APACHE_CONF_BACKUP_DIR" ]; then - APACHE_CONF_BACKUP_DIR="$CONFIG_HOME" + APACHE_CONF_BACKUP_DIR="$LE_CONFIG_HOME" fi if [ -z "$USER_AGENT" ]; then @@ -1715,7 +1717,7 @@ _initpath() { fi if [ -z "$HTTP_HEADER" ]; then - HTTP_HEADER="$CONFIG_HOME/http.header" + HTTP_HEADER="$LE_CONFIG_HOME/http.header" fi _OLD_ACCOUNT_KEY="$LE_WORKING_DIR/account.key" @@ -1731,7 +1733,7 @@ _initpath() { ACCOUNT_JSON_PATH="$_DEFAULT_ACCOUNT_JSON_PATH" fi - _DEFAULT_CERT_HOME="$CONFIG_HOME" + _DEFAULT_CERT_HOME="$LE_CONFIG_HOME" if [ -z "$CERT_HOME" ]; then CERT_HOME="$_DEFAULT_CERT_HOME" fi @@ -3418,8 +3420,8 @@ uninstallcronjob() { LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')" _info LE_WORKING_DIR "$LE_WORKING_DIR" if _contains "$cr" "--config-home"; then - CONFIG_HOME="$(echo "$cr" | cut -d ' ' -f 11 | tr -d '"')" - _debug CONFIG_HOME "$CONFIG_HOME" + LE_CONFIG_HOME="$(echo "$cr" | cut -d ' ' -f 11 | tr -d '"')" + _debug LE_CONFIG_HOME "$LE_CONFIG_HOME" fi fi _initpath @@ -3701,6 +3703,9 @@ _installalias() { fi _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" + if [ "$_c_home" ]; then + _setopt "$_envfile" "export LE_CONFIG_HOME" "=" "\"$LE_CONFIG_HOME\"" + fi _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" _profile="$(_detect_profile)" @@ -3719,6 +3724,9 @@ _installalias() { if [ -f "$_csh_profile" ]; then _info "Installing alias to '$_csh_profile'" _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" + if [ "$_c_home" ]; then + _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" + fi _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" _setopt "$_csh_profile" "source \"$_cshfile\"" fi @@ -3728,6 +3736,9 @@ _installalias() { if [ -f "$_tcsh_profile" ]; then _info "Installing alias to '$_tcsh_profile'" _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" + if [ "$_c_home" ]; then + _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" + fi _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" _setopt "$_tcsh_profile" "source \"$_cshfile\"" fi @@ -3781,12 +3792,12 @@ install() { chmod 700 "$LE_WORKING_DIR" - if ! mkdir -p "$CONFIG_HOME"; then - _err "Can not create config dir: $CONFIG_HOME" + if ! mkdir -p "$LE_CONFIG_HOME"; then + _err "Can not create config dir: $LE_CONFIG_HOME" return 1 fi - chmod 700 "$CONFIG_HOME" + chmod 700 "$LE_CONFIG_HOME" cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" @@ -3856,7 +3867,7 @@ uninstall() { _uninstallalias rm -f "$LE_WORKING_DIR/$PROJECT_ENTRY" - _info "The keys and certs are in \"$(__green "$CONFIG_HOME")\", you can remove them by yourself." + _info "The keys and certs are in \"$(__green "$LE_CONFIG_HOME")\", you can remove them by yourself." } @@ -4344,7 +4355,7 @@ _process() { ;; --config-home) _confighome="$2" - CONFIG_HOME="$_confighome" + LE_CONFIG_HOME="$_confighome" shift ;; --useragent) From be83a6a37ac7cfba048db5e06b04b9486ebf1fd5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 21 Jan 2017 12:40:43 +0800 Subject: [PATCH 086/620] minor, fix alias --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 33fd6201..d9cd0228 100755 --- a/acme.sh +++ b/acme.sh @@ -3699,14 +3699,14 @@ _installalias() { fi if [ "$_c_home" ]; then - _c_entry="--config-home '$_c_home'" + _c_entry=" --config-home '$_c_home'" fi _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" if [ "$_c_home" ]; then _setopt "$_envfile" "export LE_CONFIG_HOME" "=" "\"$LE_CONFIG_HOME\"" fi - _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" + _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" _profile="$(_detect_profile)" if [ "$_profile" ]; then @@ -3727,7 +3727,7 @@ _installalias() { if [ "$_c_home" ]; then _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" fi - _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" + _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" _setopt "$_csh_profile" "source \"$_cshfile\"" fi @@ -3739,7 +3739,7 @@ _installalias() { if [ "$_c_home" ]; then _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" fi - _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY $_c_entry\"" + _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" _setopt "$_tcsh_profile" "source \"$_cshfile\"" fi From 78f0201dfafede2ef68a5776ab5f80a6d196d3af Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 21 Jan 2017 13:32:12 +0800 Subject: [PATCH 087/620] add --remove --- acme.sh | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d9cd0228..2dc16e5a 100755 --- a/acme.sh +++ b/acme.sh @@ -3431,7 +3431,7 @@ uninstallcronjob() { revoke() { Le_Domain="$1" if [ -z "$Le_Domain" ]; then - _usage "Usage: $PROJECT_ENTRY --revoke -d domain.com" + _usage "Usage: $PROJECT_ENTRY --revoke -d domain.com [--ecc]" return 1 fi @@ -3489,6 +3489,37 @@ revoke() { return 1 } +#domain ecc +remove() { + Le_Domain="$1" + if [ -z "$Le_Domain" ]; then + _usage "Usage: $PROJECT_ENTRY --remove -d domain.com [--ecc]" + return 1 + fi + + _isEcc="$2" + + _initpath "$Le_Domain" "$_isEcc" + _removed_conf="$DOMAIN_CONF.removed" + if [ ! -f "$DOMAIN_CONF" ]; then + if [ -f "$_removed_conf" ]; then + _err "$Le_Domain is already removed, You can remove the folder by yourself: $DOMAIN_PATH" + else + _err "$Le_Domain is not a issued domain, skip." + fi + return 1 + fi + + if mv "$DOMAIN_CONF" "$_removed_conf"; then + _info "$Le_Domain is removed, the key and cert files are in $(__green $DOMAIN_PATH )" + _info "You can remove them by yourself." + return 0 + else + _err "Remove $Le_Domain failed." + return 1 + fi +} + #domain vtype _deactivate() { _d_domain="$1" @@ -3944,6 +3975,7 @@ Commands: --renew, -r Renew a cert. --renew-all Renew all the certs. --revoke Revoke a cert. + --remove Remove the cert from $PROJECT --list List all the certs. --showcsr Show the content of a csr. --install-cronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. @@ -4176,6 +4208,9 @@ _process() { --revoke) _CMD="revoke" ;; + --remove) + _CMD="remove" + ;; --list) _CMD="list" ;; @@ -4535,6 +4570,9 @@ _process() { revoke) revoke "$_domain" "$_ecc" ;; + remove) + remove "$_domain" "$_ecc" + ;; deactivate) deactivate "$_domain,$_altdomains" ;; From 68aea3af9e87d40df689dca19c5a97cd4c5b25bc Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 21 Jan 2017 14:19:01 +0800 Subject: [PATCH 088/620] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 2dc16e5a..35b0cc7a 100755 --- a/acme.sh +++ b/acme.sh @@ -3511,7 +3511,7 @@ remove() { fi if mv "$DOMAIN_CONF" "$_removed_conf"; then - _info "$Le_Domain is removed, the key and cert files are in $(__green $DOMAIN_PATH )" + _info "$Le_Domain is removed, the key and cert files are in $(__green $DOMAIN_PATH)" _info "You can remove them by yourself." return 0 else From 25555b8c3ead26d7fb58ac8519f73efc61b786f6 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 22 Jan 2017 18:11:32 +0800 Subject: [PATCH 089/620] pass the paths to reload cmd --- acme.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 35b0cc7a..33599448 100755 --- a/acme.sh +++ b/acme.sh @@ -3349,9 +3349,14 @@ _installcert() { fi if [ "$Le_ReloadCmd" ]; then - _info "Run Le_ReloadCmd: $Le_ReloadCmd" - if (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd"); then + if ( + export CERT_PATH + export CERT_KEY_PATH + export CA_CERT_PATH + export CERT_FULLCHAIN_PATH + cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd" + ); then _info "$(__green "Reload success")" else _err "Reload error for :$Le_Domain" From 839bf0e2c9ccf97e6acc8a6cccc0c3d5b2e5600f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 22 Jan 2017 18:48:21 +0800 Subject: [PATCH 090/620] fix format --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index 33599448..7ec84e6f 100755 --- a/acme.sh +++ b/acme.sh @@ -3351,12 +3351,12 @@ _installcert() { if [ "$Le_ReloadCmd" ]; then _info "Run Le_ReloadCmd: $Le_ReloadCmd" if ( - export CERT_PATH - export CERT_KEY_PATH - export CA_CERT_PATH - export CERT_FULLCHAIN_PATH - cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd" - ); then + export CERT_PATH + export CERT_KEY_PATH + export CA_CERT_PATH + export CERT_FULLCHAIN_PATH + cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd" + ); then _info "$(__green "Reload success")" else _err "Reload error for :$Le_Domain" From 11927a768eca90138dd123391d7a55cece468b85 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 29 Jan 2017 11:47:04 +0800 Subject: [PATCH 091/620] minor, rename --- acme.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index 7ec84e6f..eb3164f1 100755 --- a/acme.sh +++ b/acme.sh @@ -868,7 +868,7 @@ createCSR() { } -_urlencode() { +_url_replace() { tr '/+' '_-' | tr -d '= ' } @@ -935,7 +935,7 @@ _calcjwk() { modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" - n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)" + n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)" _debug3 n "$n" jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' @@ -990,14 +990,14 @@ _calcjwk() { x="$(printf "%s" "$pubtext" | cut -d : -f 2-"$xend")" _debug3 x "$x" - x64="$(printf "%s" "$x" | tr -d : | _h2b | _base64 | _urlencode)" + x64="$(printf "%s" "$x" | tr -d : | _h2b | _base64 | _url_replace)" _debug3 x64 "$x64" xend=$(_math "$xend" + 1) y="$(printf "%s" "$pubtext" | cut -d : -f "$xend"-10000)" _debug3 y "$y" - y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _urlencode)" + y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _url_replace)" _debug3 y64 "$y64" jwk='{"crv": "'$crv'", "kty": "EC", "x": "'$x64'", "y": "'$y64'"}' @@ -1241,7 +1241,7 @@ _send_signed_request() { return 1 fi - payload64=$(printf "%s" "$payload" | _base64 | _urlencode) + payload64=$(printf "%s" "$payload" | _base64 | _url_replace) _debug3 payload64 "$payload64" if [ -z "$_CACHED_NONCE" ]; then @@ -1267,7 +1267,7 @@ _send_signed_request() { protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" _debug3 protected "$protected" - protected64="$(printf "%s" "$protected" | _base64 | _urlencode)" + protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" _debug3 protected64 "$protected64" if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then @@ -1276,7 +1276,7 @@ _send_signed_request() { fi _debug3 _sig_t "$_sig_t" - sig="$(printf "%s" "$_sig_t" | _urlencode)" + sig="$(printf "%s" "$_sig_t" | _url_replace)" _debug3 sig "$sig" body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" @@ -2005,7 +2005,7 @@ _clearupdns() { 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" | _urlencode)" + txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" _debug txt "$txt" if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then _info "$d is already verified, skip $vtype." @@ -2549,7 +2549,7 @@ issue() { if [ -z "$thumbprint" ]; then accountkey_json=$(printf "%s" "$jwk" | tr -d ' ') - thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode) + thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _url_replace) fi entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" @@ -2600,7 +2600,7 @@ issue() { dnsadded='0' txtdomain="_acme-challenge.$d" _debug txtdomain "$txtdomain" - txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _urlencode)" + txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" _debug txt "$txt" d_api="$(_findHook "$d" dnsapi "$_currentRoot")" @@ -2875,7 +2875,7 @@ issue() { _clearup _info "Verify finished, start to sign." - der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _urlencode)" + der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." @@ -3453,7 +3453,7 @@ revoke() { return 1 fi - cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _urlencode)" + cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _url_replace)" if [ -z "$cert" ]; then _err "Cert for $Le_Domain is empty found, skip." From 542d7977db1479f9383561ae1657dcfb2ecfcb2c Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 30 Jan 2017 12:07:50 +0800 Subject: [PATCH 092/620] add new _url_encode --- acme.sh | 248 ++++++++++++++++++++++++++++++++++++++++++++-- dnsapi/dns_ali.sh | 2 +- dnsapi/dns_aws.sh | 2 +- dnsapi/dns_me.sh | 2 +- 4 files changed, 242 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index eb3164f1..22d49351 100755 --- a/acme.sh +++ b/acme.sh @@ -336,15 +336,245 @@ _h2b() { done } -#hex string -_hex() { - _str="$1" - _str_len=${#_str} - _h_i=1 - while [ "$_h_i" -le "$_str_len" ]; do - _str_c="$(printf "%s" "$_str" | cut -c "$_h_i")" - printf "%02x" "'$_str_c" - _h_i="$(_math "$_h_i" + 1)" +_is_solaris() { + _contains "${__OS__:=$(uname -a)}" "solaris" || _contains "${__OS__:=$(uname -a)}" "SunOS" +} + +#stdin output hexstr splited by one space +#input:"abc" +#output: " 61 62 63" +_hex_dump() { + if _is_solaris; then + od -A n -v -t x1 | tr -d "\r\n\t" | tr -s " " | tr -d "\n" + else + od -A n -v -t x1 | tr -d "\r\n\t" | tr -s " " | sed "s/ $//" | tr -d "\n" + fi +} + +#url encode, no-preserved chars +#A B C D E F G H I J K L M N O P Q R S T U V W X Y Z +#41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a + +#a b c d e f g h i j k l m n o p q r s t u v w x y z +#61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a + +#0 1 2 3 4 5 6 7 8 9 - _ . ~ +#30 31 32 33 34 35 36 37 38 39 2d 5f 2e 7e + +#stdin stdout +_url_encode() { + _hex_str=$(_hex_dump) + _debug3 "_url_encode" + _debug3 "_hex_str" "$_hex_str" + for _hex_code in $_hex_str; do + #upper case + case "${_hex_code}" in + "41" ) + printf "%s" "A" + ;; + "42" ) + printf "%s" "B" + ;; + "43" ) + printf "%s" "C" + ;; + "44" ) + printf "%s" "D" + ;; + "45" ) + printf "%s" "E" + ;; + "46" ) + printf "%s" "F" + ;; + "47" ) + printf "%s" "G" + ;; + "48" ) + printf "%s" "H" + ;; + "49" ) + printf "%s" "I" + ;; + "4a" ) + printf "%s" "J" + ;; + "4b" ) + printf "%s" "K" + ;; + "4c" ) + printf "%s" "L" + ;; + "4d" ) + printf "%s" "M" + ;; + "4e" ) + printf "%s" "N" + ;; + "4f" ) + printf "%s" "O" + ;; + "50" ) + printf "%s" "P" + ;; + "51" ) + printf "%s" "Q" + ;; + "52" ) + printf "%s" "R" + ;; + "53" ) + printf "%s" "S" + ;; + "54" ) + printf "%s" "T" + ;; + "55" ) + printf "%s" "U" + ;; + "56" ) + printf "%s" "V" + ;; + "57" ) + printf "%s" "W" + ;; + "58" ) + printf "%s" "X" + ;; + "59" ) + printf "%s" "Y" + ;; + "5a" ) + printf "%s" "Z" + ;; + + #lower case + "61" ) + printf "%s" "a" + ;; + "62" ) + printf "%s" "b" + ;; + "63" ) + printf "%s" "c" + ;; + "64" ) + printf "%s" "d" + ;; + "65" ) + printf "%s" "e" + ;; + "66" ) + printf "%s" "f" + ;; + "67" ) + printf "%s" "g" + ;; + "68" ) + printf "%s" "h" + ;; + "69" ) + printf "%s" "i" + ;; + "6a" ) + printf "%s" "j" + ;; + "6b" ) + printf "%s" "k" + ;; + "6c" ) + printf "%s" "l" + ;; + "6d" ) + printf "%s" "m" + ;; + "6e" ) + printf "%s" "n" + ;; + "6f" ) + printf "%s" "o" + ;; + "70" ) + printf "%s" "p" + ;; + "71" ) + printf "%s" "q" + ;; + "72" ) + printf "%s" "r" + ;; + "73" ) + printf "%s" "s" + ;; + "74" ) + printf "%s" "t" + ;; + "75" ) + printf "%s" "u" + ;; + "76" ) + printf "%s" "v" + ;; + "77" ) + printf "%s" "w" + ;; + "78" ) + printf "%s" "x" + ;; + "79" ) + printf "%s" "y" + ;; + "7a" ) + printf "%s" "z" + ;; + #numbers + "30" ) + printf "%s" "0" + ;; + "31" ) + printf "%s" "1" + ;; + "32" ) + printf "%s" "2" + ;; + "33" ) + printf "%s" "3" + ;; + "34" ) + printf "%s" "4" + ;; + "35" ) + printf "%s" "5" + ;; + "36" ) + printf "%s" "6" + ;; + "37" ) + printf "%s" "7" + ;; + "38" ) + printf "%s" "8" + ;; + "39" ) + printf "%s" "9" + ;; + "2d" ) + printf "%s" "-" + ;; + "5f" ) + printf "%s" "_" + ;; + "2e" ) + printf "%s" "." + ;; + "7e" ) + printf "%s" "~" + ;; + #other hex + *) + printf '%%%s' "$_hex_code" + ;; + esac done } diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh index 98c56f87..9b6f85c8 100644 --- a/dnsapi/dns_ali.sh +++ b/dnsapi/dns_ali.sh @@ -67,7 +67,7 @@ _get_root() { } _ali_rest() { - signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(_hex "$Ali_Secret&")" | _base64) + signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | sed "s/ //g")" | _base64) signature=$(_ali_urlencode "$signature") url="$Ali_API?$query&Signature=$signature" diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 59ef6181..5e7b34f5 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -183,7 +183,7 @@ aws_rest() { _debug2 kSecret "$kSecret" - kSecretH="$(_hex "$kSecret")" + kSecretH="$(printf "%s" "$kSecret" | _hex_dump | sed "s/ //g")" _debug2 kSecretH "$kSecretH" kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 9fe6baf8..c6bec70d 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -124,7 +124,7 @@ _me_rest() { _debug "$ep" cdate=$(date -u +"%a, %d %b %Y %T %Z") - hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(_hex "$ME_Secret")" hex) + hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(printf "%s" "$ME_Secret" | _hex_dump | sed "s/ //g")" hex) export _H1="x-dnsme-apiKey: $ME_Key" export _H2="x-dnsme-requestDate: $cdate" From c3b1eb0837cd5585709d32f8b337158d18bc38eb Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 30 Jan 2017 12:25:56 +0800 Subject: [PATCH 093/620] fix format --- acme.sh | 406 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 203 insertions(+), 203 deletions(-) diff --git a/acme.sh b/acme.sh index 22d49351..cf82153a 100755 --- a/acme.sh +++ b/acme.sh @@ -369,211 +369,211 @@ _url_encode() { for _hex_code in $_hex_str; do #upper case case "${_hex_code}" in - "41" ) - printf "%s" "A" - ;; - "42" ) - printf "%s" "B" - ;; - "43" ) - printf "%s" "C" - ;; - "44" ) - printf "%s" "D" - ;; - "45" ) - printf "%s" "E" - ;; - "46" ) - printf "%s" "F" - ;; - "47" ) - printf "%s" "G" - ;; - "48" ) - printf "%s" "H" - ;; - "49" ) - printf "%s" "I" - ;; - "4a" ) - printf "%s" "J" - ;; - "4b" ) - printf "%s" "K" - ;; - "4c" ) - printf "%s" "L" - ;; - "4d" ) - printf "%s" "M" - ;; - "4e" ) - printf "%s" "N" - ;; - "4f" ) - printf "%s" "O" - ;; - "50" ) - printf "%s" "P" - ;; - "51" ) - printf "%s" "Q" - ;; - "52" ) - printf "%s" "R" - ;; - "53" ) - printf "%s" "S" - ;; - "54" ) - printf "%s" "T" - ;; - "55" ) - printf "%s" "U" - ;; - "56" ) - printf "%s" "V" - ;; - "57" ) - printf "%s" "W" - ;; - "58" ) - printf "%s" "X" - ;; - "59" ) - printf "%s" "Y" - ;; - "5a" ) - printf "%s" "Z" - ;; + "41") + printf "%s" "A" + ;; + "42") + printf "%s" "B" + ;; + "43") + printf "%s" "C" + ;; + "44") + printf "%s" "D" + ;; + "45") + printf "%s" "E" + ;; + "46") + printf "%s" "F" + ;; + "47") + printf "%s" "G" + ;; + "48") + printf "%s" "H" + ;; + "49") + printf "%s" "I" + ;; + "4a") + printf "%s" "J" + ;; + "4b") + printf "%s" "K" + ;; + "4c") + printf "%s" "L" + ;; + "4d") + printf "%s" "M" + ;; + "4e") + printf "%s" "N" + ;; + "4f") + printf "%s" "O" + ;; + "50") + printf "%s" "P" + ;; + "51") + printf "%s" "Q" + ;; + "52") + printf "%s" "R" + ;; + "53") + printf "%s" "S" + ;; + "54") + printf "%s" "T" + ;; + "55") + printf "%s" "U" + ;; + "56") + printf "%s" "V" + ;; + "57") + printf "%s" "W" + ;; + "58") + printf "%s" "X" + ;; + "59") + printf "%s" "Y" + ;; + "5a") + printf "%s" "Z" + ;; - #lower case - "61" ) - printf "%s" "a" - ;; - "62" ) - printf "%s" "b" - ;; - "63" ) - printf "%s" "c" - ;; - "64" ) - printf "%s" "d" - ;; - "65" ) - printf "%s" "e" - ;; - "66" ) - printf "%s" "f" - ;; - "67" ) - printf "%s" "g" - ;; - "68" ) - printf "%s" "h" - ;; - "69" ) - printf "%s" "i" - ;; - "6a" ) - printf "%s" "j" - ;; - "6b" ) - printf "%s" "k" - ;; - "6c" ) - printf "%s" "l" - ;; - "6d" ) - printf "%s" "m" - ;; - "6e" ) - printf "%s" "n" - ;; - "6f" ) - printf "%s" "o" - ;; - "70" ) - printf "%s" "p" - ;; - "71" ) - printf "%s" "q" - ;; - "72" ) - printf "%s" "r" - ;; - "73" ) - printf "%s" "s" - ;; - "74" ) - printf "%s" "t" - ;; - "75" ) - printf "%s" "u" - ;; - "76" ) - printf "%s" "v" - ;; - "77" ) - printf "%s" "w" - ;; - "78" ) - printf "%s" "x" - ;; - "79" ) - printf "%s" "y" - ;; - "7a" ) - printf "%s" "z" - ;; - #numbers - "30" ) - printf "%s" "0" - ;; - "31" ) - printf "%s" "1" - ;; - "32" ) - printf "%s" "2" - ;; - "33" ) - printf "%s" "3" - ;; - "34" ) - printf "%s" "4" - ;; - "35" ) - printf "%s" "5" - ;; - "36" ) - printf "%s" "6" - ;; - "37" ) - printf "%s" "7" - ;; - "38" ) - printf "%s" "8" - ;; - "39" ) - printf "%s" "9" - ;; - "2d" ) - printf "%s" "-" - ;; - "5f" ) - printf "%s" "_" - ;; - "2e" ) - printf "%s" "." - ;; - "7e" ) - printf "%s" "~" - ;; - #other hex + #lower case + "61") + printf "%s" "a" + ;; + "62") + printf "%s" "b" + ;; + "63") + printf "%s" "c" + ;; + "64") + printf "%s" "d" + ;; + "65") + printf "%s" "e" + ;; + "66") + printf "%s" "f" + ;; + "67") + printf "%s" "g" + ;; + "68") + printf "%s" "h" + ;; + "69") + printf "%s" "i" + ;; + "6a") + printf "%s" "j" + ;; + "6b") + printf "%s" "k" + ;; + "6c") + printf "%s" "l" + ;; + "6d") + printf "%s" "m" + ;; + "6e") + printf "%s" "n" + ;; + "6f") + printf "%s" "o" + ;; + "70") + printf "%s" "p" + ;; + "71") + printf "%s" "q" + ;; + "72") + printf "%s" "r" + ;; + "73") + printf "%s" "s" + ;; + "74") + printf "%s" "t" + ;; + "75") + printf "%s" "u" + ;; + "76") + printf "%s" "v" + ;; + "77") + printf "%s" "w" + ;; + "78") + printf "%s" "x" + ;; + "79") + printf "%s" "y" + ;; + "7a") + printf "%s" "z" + ;; + #numbers + "30") + printf "%s" "0" + ;; + "31") + printf "%s" "1" + ;; + "32") + printf "%s" "2" + ;; + "33") + printf "%s" "3" + ;; + "34") + printf "%s" "4" + ;; + "35") + printf "%s" "5" + ;; + "36") + printf "%s" "6" + ;; + "37") + printf "%s" "7" + ;; + "38") + printf "%s" "8" + ;; + "39") + printf "%s" "9" + ;; + "2d") + printf "%s" "-" + ;; + "5f") + printf "%s" "_" + ;; + "2e") + printf "%s" "." + ;; + "7e") + printf "%s" "~" + ;; + #other hex *) - printf '%%%s' "$_hex_code" - ;; + printf '%%%s' "$_hex_code" + ;; esac done } From 0899803294d2bbebda8e098b5022d3fd808049bb Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 30 Jan 2017 14:29:40 +0800 Subject: [PATCH 094/620] add my twitter --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 9b5891c9..7b9d0025 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ It's probably the `easiest&smallest&smartest` shell script to automatically issu Wiki: https://github.com/Neilpang/acme.sh/wiki +Twitter: [@neilpangxa](https://twitter.com/neilpangxa) + + # [中文说明](https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E) From 59182dbc97dbbf017441a46c53f6dcac837431e6 Mon Sep 17 00:00:00 2001 From: Philipp Grosswiler Date: Tue, 31 Jan 2017 10:43:30 +0700 Subject: [PATCH 095/620] Removed Linode CLI dependency. --- dnsapi/dns_linode.sh | 176 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 152 insertions(+), 24 deletions(-) diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index 0af1ad7c..e1c32204 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -1,6 +1,13 @@ #!/usr/bin/env bash -linode_cmd="/usr/bin/linode" +#Author: Philipp Grosswiler + +#How to create the Linode API key: +#Sign into your Linode account and go to this page: https://manager.linode.com/profile/api +#Then add an API key with label ACME and copy the new key. +#export LINODE_API_KEY="..." + +LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action=" ######## Public functions ##################### @@ -9,52 +16,173 @@ dns_linode_add() { fulldomain="${1}" txtvalue="${2}" + if ! _Linode_API; then + return 1 + fi + _info "Using Linode" _debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'" - domain=$(printf "%s" "${fulldomain}" | cut -d . -f 3-999) - name=$(printf "%s" "${fulldomain}" | cut -d . -f 1-2) - _debug name "${name}" - _debug domain "${domain}" + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "Domain does not exist." + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _parameters="&DomainID=$_domain_id&Type=TXT&Name=$_sub_domain&Target=$txtvalue" + + if _rest GET "domain.resource.create" "$_parameters" && [ -n "$response" ]; then + _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) + _debug _resource_id "$_resource_id" + + if [ -z "$_resource_id" ]; then + _err "Error adding the domain resource." + return 1 + fi - _Linode_CLI && _Linode_addTXT + _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}'" - domain=$(printf "%s" "${fulldomain}" | cut -d . -f 3-999) - name=$(printf "%s" "${fulldomain}" | cut -d . -f 1-2) - _debug name "${name}" - _debug domain "${domain}" + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "Domain does not exist." + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _parameters="&DomainID=$_domain_id" + + if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then + response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + + resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" + if [ "$resource" ]; then + _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"RESOURCEID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "$_resource_id" ]; then + _debug _resource_id "$_resource_id" - _Linode_CLI && _Linode_rmTXT + _parameters="&DomainID=$_domain_id&ResourceID=$_resource_id" + + if _rest GET "domain.resource.delete" "$_parameters" && [ -n "$response" ]; then + _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) + _debug _resource_id "$_resource_id" + + if [ -z "$_resource_id" ]; then + _err "Error deleting the domain resource." + return 1 + fi + + _info "Domain resource successfully deleted." + return 0 + fi + fi + + return 1 + fi + + return 0 + fi + + return 1 } #################### Private functions below ################################## -_Linode_CLI() { - if [ ! -f "${linode_cmd}" ]; then - _err "Please install the Linode CLI package and set it up accordingly before using this DNS API." +_Linode_API() { + if [ -z "$LINODE_API_KEY" ]; then + LINODE_API_KEY="" + + _err "You didn't specify the Linode API key yet." + _err "Please create your key and try again." + return 1 fi + + _saveaccountconf LINODE_API_KEY "$LINODE_API_KEY" } -_Linode_addTXT() { - _debug "$linode_cmd domain record-update ${domain} TXT ${name} --target ${txtvalue}" - $linode_cmd domain record-update ${domain} TXT ${name} --target ${txtvalue} +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=12345 +_get_root() { + domain=$1 + i=2 + p=1 + + if _rest GET "domain.list"; then + response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi - if [ $? -ne 0 ]; then - _debug "$linode_cmd domain record-create ${domain} TXT ${name} ${txtvalue}" - $linode_cmd domain record-create ${domain} TXT ${name} ${txtvalue} + hostedzone="$(echo "$response" | _egrep_o "{.*\"DOMAIN\":\s*\"$h\".*}")" + if [ "$hostedzone" ]; then + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"DOMAINID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done fi + return 1 } -_Linode_rmTXT() { - _debug "$linode_cmd domain record-delete ${domain} TXT ${name}" - $linode_cmd domain record-delete ${domain} TXT ${name} -} +#method method action data +_rest() { + mtd="$1" + ep="$2" + data="$3" + + _debug mtd "$mtd" + _debug ep "$ep" + + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + + if [ "$mtd" != "GET" ]; then + # both POST and DELETE. + _debug data "$data" + response="$(_post "$data" "$LINODE_API_URL$ep" "" "$mtd")" + else + response="$(_get "$LINODE_API_URL$ep$data")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} \ No newline at end of file From dd17ac5045a8dc7832d90644271937f4550e793e Mon Sep 17 00:00:00 2001 From: Philipp Grosswiler Date: Tue, 31 Jan 2017 10:56:34 +0700 Subject: [PATCH 096/620] Added instructions on how to get the Linode API key. --- dnsapi/README.md | 16 +++++++++------- dnsapi/dns_linode.sh | 7 +------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 1895d376..df728acc 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -259,23 +259,25 @@ when needed. ## 14. Use Linode domain API -You will need to install the Linode CLI and set it up accordingly. +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) -[https://www.linode.com/docs/platform/linode-cli](https://www.linode.com/docs/platform/linode-cli) +Then add an API key with label *ACME* and copy the new key. -Follow the installation instructions appropriate for your platform and then run the configuration. - -```linode configure +```sh +export LINODE_API_KEY="..." ``` -Make sure Linode CLI is working correctly before proceeding. - Due to the reload time of any changes in the DNS records, we have to use the `dnssleep` option to wait at least 15 minutes for the changes to take effect. +Ok, let's issue a cert now: + ```sh acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.com ``` +The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index e1c32204..501a51af 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -1,12 +1,7 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh #Author: Philipp Grosswiler -#How to create the Linode API key: -#Sign into your Linode account and go to this page: https://manager.linode.com/profile/api -#Then add an API key with label ACME and copy the new key. -#export LINODE_API_KEY="..." - LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action=" ######## Public functions ##################### From bcf96608d123d2cfd0f810b0c1138e0f37a4efea Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 12:38:37 +0800 Subject: [PATCH 097/620] fix for solaris --- dnsapi/dns_cx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 9c032fd7..fa821f76 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -155,7 +155,7 @@ _get_root() { fi if _contains "$response" "$h."; then - seg=$(printf "%s\n" "$response" | _egrep_o '[^{]*"'"$h"'."[^}]*}') + seg=$(printf "%s\n" "$response" | _egrep_o '"id":[^{]*"'"$h"'."[^}]*}') _debug seg "$seg" _domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") _debug _domain_id "$_domain_id" From 646c0bfcb9290a98a8b835897114860e14376560 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 12:51:59 +0800 Subject: [PATCH 098/620] fix for solaris --- dnsapi/dns_cx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index fa821f76..2b6d5691 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -82,7 +82,7 @@ existing_records() { return 1 fi - seg=$(printf "%s\n" "$response" | _egrep_o '[^{]*host":"'"$_sub_domain"'"[^}]*\}') + seg=$(printf "%s\n" "$response" | _egrep_o '"record_id":[^{]*host":"'"$_sub_domain"'"[^}]*\}') _debug seg "$seg" if [ -z "$seg" ]; then return 0 From 1c22c2f76a0a7c0b3c03c40aaba0d0c6fd7723f3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 14:04:40 +0800 Subject: [PATCH 099/620] fix for solaris --- dnsapi/dns_ali.sh | 2 +- dnsapi/dns_aws.sh | 2 +- dnsapi/dns_me.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh index 9b6f85c8..f796f076 100644 --- a/dnsapi/dns_ali.sh +++ b/dnsapi/dns_ali.sh @@ -67,7 +67,7 @@ _get_root() { } _ali_rest() { - signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | sed "s/ //g")" | _base64) + signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | tr -d " ")" | _base64) signature=$(_ali_urlencode "$signature") url="$Ali_API?$query&Signature=$signature" diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 5e7b34f5..1308c507 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -183,7 +183,7 @@ aws_rest() { _debug2 kSecret "$kSecret" - kSecretH="$(printf "%s" "$kSecret" | _hex_dump | sed "s/ //g")" + kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")" _debug2 kSecretH "$kSecretH" kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index c6bec70d..f63621d9 100755 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -124,7 +124,7 @@ _me_rest() { _debug "$ep" cdate=$(date -u +"%a, %d %b %Y %T %Z") - hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(printf "%s" "$ME_Secret" | _hex_dump | sed "s/ //g")" hex) + hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(printf "%s" "$ME_Secret" | _hex_dump | tr -d " ")" hex) export _H1="x-dnsme-apiKey: $ME_Key" export _H2="x-dnsme-requestDate: $cdate" From c070407ab2dfd784f57188a2a34322aed020fc1b Mon Sep 17 00:00:00 2001 From: Philipp Grosswiler Date: Tue, 31 Jan 2017 13:38:16 +0700 Subject: [PATCH 100/620] Fixed Travis CI complaining about missing newline at end of file. --- dnsapi/dns_linode.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index 501a51af..6d54e6c1 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -180,4 +180,4 @@ _rest() { fi _debug2 response "$response" return 0 -} \ No newline at end of file +} From bb6326f4d423b9fe6b6677ffb058711724376fcb Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 15:57:43 +0800 Subject: [PATCH 101/620] fix for solaris --- 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 1308c507..555bd70b 100644 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -93,7 +93,7 @@ _get_root() { fi if _contains "$response" "$h."; then - hostedzone="$(echo "$response" | sed 's//\n&/g' | _egrep_o ".*?$h.<.Name>.*?<.HostedZone>")" + hostedzone="$(echo "$response" | _egrep_o "[^<]*<.Id>$h.<.Name>.*<.HostedZone>")" _debug hostedzone "$hostedzone" if [ -z "$hostedzone" ]; then _err "Error, can not get hostedzone." From 5d833336d33ca82eb3f1634d83e21b8d805bf88b Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 18:41:32 +0800 Subject: [PATCH 102/620] minor --- dnsapi/dns_lua.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 47f4497a..9506929c 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -46,12 +46,12 @@ dns_lua_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l) + count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l | tr -s " ") _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then + if _contains "$response" "$fulldomain"; then _info "Added" #todo: check if the record takes effect return 0 @@ -99,6 +99,7 @@ _get_root() { fi while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" if [ -z "$h" ]; then #not valid return 1 @@ -106,6 +107,7 @@ _get_root() { if _contains "$response" "\"name\":\"$h\""; then _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$h\"" | cut -d : -f 2 | cut -d , -f 1) + _debug _domain_id "$_domain_id" if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain="$h" From 05cf405cb53a2ea1bc55d29535beefaffd8dbe97 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 18:46:24 +0800 Subject: [PATCH 103/620] minor --- dnsapi/dns_lua.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 9506929c..be77b9d9 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -46,7 +46,7 @@ dns_lua_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l | tr -s " ") + count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l | tr -d " ") _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" From 53fa16d39f314a43e60b47c923cd5d854742e539 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 18:59:00 +0800 Subject: [PATCH 104/620] minor --- dnsapi/dns_lua.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index be77b9d9..211dbb04 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -46,7 +46,7 @@ dns_lua_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l | tr -d " ") + count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ") _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" From ab5c1b0a3a6843954ee959c4700f8e422c5b8002 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 19:03:29 +0800 Subject: [PATCH 105/620] minor --- dnsapi/dns_lua.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 211dbb04..0dd97fc3 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -63,7 +63,7 @@ dns_lua_add() { _err "Add txt record error." else _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | cut -d: -f2 | cut -d, -f1) + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1) _debug "record_id" "$record_id" _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"ttl\":120}" From d78ba322bfbbaf93659c8b905b50431b3a7d14f4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 19:22:14 +0800 Subject: [PATCH 106/620] fix update --- dnsapi/dns_lua.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 0dd97fc3..42d55e84 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -66,8 +66,8 @@ dns_lua_add() { record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1) _debug "record_id" "$record_id" - _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"ttl\":120}" - if [ "$?" = "0" ]; then + _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":$record_id,\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":$_domain_id,\"ttl\":120}" + if [ "$?" = "0" ] && _contains "$response" "updated_at" ; then _info "Updated!" #todo: check if the record takes effect return 0 From 5f8daeeb6d987687ac896c128c327c2096b02009 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 31 Jan 2017 20:03:41 +0800 Subject: [PATCH 107/620] minor, a better hex_dump --- acme.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index cf82153a..e5728b3c 100755 --- a/acme.sh +++ b/acme.sh @@ -344,11 +344,7 @@ _is_solaris() { #input:"abc" #output: " 61 62 63" _hex_dump() { - if _is_solaris; then - od -A n -v -t x1 | tr -d "\r\n\t" | tr -s " " | tr -d "\n" - else - od -A n -v -t x1 | tr -d "\r\n\t" | tr -s " " | sed "s/ $//" | tr -d "\n" - fi + od -A n -v -t x1 | tr -d "\r\t" | tr -s " " | sed "s/ $//" | tr -d "\n" } #url encode, no-preserved chars From 600a23514029477e794f356f4158ba36b3311a8f Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 31 Jan 2017 23:16:04 -0500 Subject: [PATCH 108/620] Add FreeDNS plugin --- dnsapi/dns_freedns.sh | 371 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100755 dnsapi/dns_freedns.sh diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh new file mode 100755 index 00000000..ad3f9da3 --- /dev/null +++ b/dnsapi/dns_freedns.sh @@ -0,0 +1,371 @@ +#!/usr/bin/env sh + +#This file name is "dns_freedns.sh" +#So, here must be a method dns_freedns_add() +#Which will be called by acme.sh to add the txt record to your api system. +#returns 0 means success, otherwise error. +# +#Author: David Kerr +#Report Bugs here: https://github.com/dkerr64/acme.sh +# +######## Public functions ##################### + +# Export FreeDNS userid and password in folowing variables... +# FREEDNS_User=username +# FREEDNS_Password=password +# login cookie is saved in acme account config file so userid / pw +# need to be set only when changed. + +#Usage: dns_freedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_freedns_add() { + fulldomain="$1" + txtvalue="$2" + + _info "Add TXT record using FreeDNS" + _debug "fulldomain: $fulldomain" + _debug "txtvalue: $txtvalue" + + if [ -z "$FREEDNS_User" ] || [ -z "$FREEDNS_Password" ]; then + FREEDNS_User="" + FREEDNS_Password="" + if [ -z "$FREEDNS_COOKIE" ]; then + _err "You did not specify the FreeDNS username and password yet." + _err "Please export as FREEDNS_User / FREEDNS_Password and try again." + return 1 + fi + using_cached_cookies="true" + else + FREEDNS_COOKIE="$(_freedns_login "$FREEDNS_User" "$FREEDNS_Password")" + if [ -z "$FREEDNS_COOKIE" ]; then + return 1 + fi + using_cached_cookies="false" + fi + + _debug "FreeDNS login cookies: $FREEDNS_COOKIE (cached = $using_cached_cookies)" + + _saveaccountconf FREEDNS_COOKIE "$FREEDNS_COOKIE" + + # split our full domain name into two parts... + i="$(echo "$fulldomain" | tr '.' ' ' | wc -w)" + i="$(_math "$i" - 1)" + top_domain="$(echo "$fulldomain" | cut -d. -f "$i"-100)" + i="$(_math "$i" - 1)" + sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" + + # Sometimes FreeDNS does not reurn 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 channged? If so..." + _err "Please export as FREEDNS_User / FREEDNS_Password and try again." + fi + return 1 + fi + + # Now convert the tables in the HTML to CSV. This litte gem from + # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv + subdomain_csv="$(echo "$htmlpage" \ + | grep -i -e ']*>/\n/Ig' \ + | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ + | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ + | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ + | grep 'edit.php?' \ + | grep "$top_domain")" + # 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)" + nl=' +' + i=0 + found=0 + while [ "$i" -lt "$lines" ]; do + i="$(_math "$i" + 1)" + line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")" + tmp="$(echo "$line" | cut -d ',' -f 1)" + if [ $found = 0 ] && _startswith "$tmp" "$top_domain"; then + # this line will contain DNSdomainid for the top_domain + DNSdomainid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*domain_id=//;s/>.*//')" + found=1 + else + # lines contain DNS records for all subdomains + DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')" + DNStype="$(echo "$line" | cut -d ',' -f 3)" + if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then + DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')" + # Now get current value for the TXT record. This method may + # not produce accurate results as the value field is truncated + # on this webpage. To get full value we would need to load + # another page. However we don't really need this so long as + # there is only one TXT record for the acme chalenge subdomain. + DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')" + if [ $found != 0 ]; then + break + # we are breaking out of the loop at the first match of DNS name + # and DNS type (if we are past finding the domainid). This assumes + # that there is only ever one TXT record for the LetsEncrypt/acme + # challenge subdomain. This seems to be a reasonable assumption + # as the acme client deletes the TXT record on successful validation. + fi + else + DNSname="" + DNStype="" + fi + fi + done + + _debug "DNSname: $DNSname DNStype: $DNStype DNSdomainid: $DNSdomainid DNSdataid: $DNSdataid" + _debug "DNSvalue: $DNSvalue" + + if [ -z "$DNSdomainid" ]; then + # If domain ID is empty then something went wrong (top level + # domain not found at FreeDNS). + if [ "$attempts" = "0" ]; then + # exhausted maximum retry attempts + _debug "$htmlpage" + _debug "$subdomain_csv" + _err "Domain $top_domain not found at FreeDNS" + return 1 + fi + else + # break out of the 'retry' loop... we have found our domain ID + break + fi + _info "Domain $top_domain not found at FreeDNS" + _info "Retry loading subdomain page ($attempts attempts remaining)" + done + + if [ -z "$DNSdataid" ]; then + # If data ID is empty then specific subdomain does not exist yet, need + # to create it this should always be the case as the acme client + # deletes the entry after domain is validated. + _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" + return $? + else + if [ "$txtvalue" = "$DNSvalue" ]; then + # if value in TXT record matches value requested then DNS record + # does not need to be updated. But... + # Testing value match fails. Website is truncating the value field. + # So for now we will always go down the else path. Though in theory + # should never come here anyway as the acme client deletes + # the TXT record on successful validation, so we should not even + # have found a TXT record !! + _info "No update necessary for $fulldomain at FreeDNS" + return 0 + else + # Delete the old TXT record (with the wrong value) + _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid" + if [ "$?" = "0" ]; then + # And add in new TXT record with the value provided + _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" + fi + return $? + fi + fi + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_freedns_rm() { + fulldomain="$1" + txtvalue="$2" + + _info "Delete TXT record using FreeDNS" + _debug "fulldomain: $fulldomain" + _debug "txtvalue: $txtvalue" + + # Need to read cookie from conf file again in case new value set + # during login to FreeDNS when TXT record was created. + # acme.sh does not have a _readaccountconf() fuction + FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")" + _debug "FreeDNS login cookies: $FREEDNS_COOKIE" + + # Sometimes FreeDNS does not reurn the subdomain page but rather + # returns a page regarding becoming a premium member. This usually + # happens after a period of inactivity. Immediately trying again + # returns the correct subdomain page. So, we will try twice to + # load the page and obtain our TXT record. + attempts=2 + while [ "$attempts" -gt "0" ]; do + attempts="$(_math "$attempts" - 1)" + + htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" + if [ "$?" != "0" ]; then + return 1 + fi + + # Now convert the tables in the HTML to CSV. This litte gem from + # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv + subdomain_csv="$(echo "$htmlpage" \ + | grep -i -e ']*>/\n/Ig' \ + | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ + | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ + | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ + | grep 'edit.php?' \ + | grep "$fulldomain")" + # 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)" + nl=' +' + i=0 + found=0 + while [ "$i" -lt "$lines" ]; do + i="$(_math "$i" + 1)" + line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")" + DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')" + DNStype="$(echo "$line" | cut -d ',' -f 3)" + if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then + DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')" + DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')" + _debug "DNSvalue: $DNSvalue" + # if [ "$DNSvalue" = "$txtvalue" ]; then + # Testing value match fails. Website is truncating the value + # field. So for now we will assume that there is only one TXT + # field for the sub domain and just delete it. Currently this + # is a safe assumption. + _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid" + return $? + # fi + fi + done + done + + # If we get this far we did not find a match (after two attempts) + # Not necessarily an error, but log anyway. + _debug2 "$subdomain_csv" + _info "Cannot delete TXT record for $fulldomain/$txtvalue. Does not exist at FreeDNS" + return 0 +} + +#################### Private functions below ################################## + +# usage: _freedns_login username password +# print string "cookie=value" etc. +# returns 0 success +_freedns_login() { + username="$1" + password="$2" + url="https://freedns.afraid.org/zc.php?step=2" + + _debug "Login to FreeDNS as user $username" + + htmlpage="$(_post "username=$(printf '%s' "$username" | _url_encode)&password=$(printf '%s' "$password" | _url_encode)&submit=Login&action=auth" "$url")" + + if [ "$?" != "0" ]; then + _err "FreeDNS login failed for user $username bad RC from _post" + return 1 + fi + + cookies="$(grep -i '^Set-Cookie.*dns_cookie.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" + + # if cookies is not empty then logon successful + if [ -z "$cookies" ]; then + _debug "$htmlpage" + _err "FreeDNS login failed for user $username. Check $HTTP_HEADER file" + return 1 + fi + + printf "%s" "$cookies" + return 0 +} + +# usage _freedns_retrieve_subdomain_page login_cookies +# echo page retrieved (html) +# returns 0 success +_freedns_retrieve_subdomain_page() { + export _H1="Cookie:$1" + url="https://freedns.afraid.org/subdomain/" + + _debug "Retrieve subdmoain page from FreeDNS" + + htmlpage="$(_get "$url")" + + if [ "$?" != "0" ]; then + _err "FreeDNS retrieve subdomins failed bad RC from _get" + return 1 + fi + + if [ -z "$htmlpage" ]; then + _err "FreeDNS returned empty subdomain page" + return 1 + fi + + _debug2 "$htmlpage" + + printf "%s" "$htmlpage" + return 0 +} + +# usage _freedns_add_txt_record login_cookies domain_id subdomain value +# returns 0 success +_freedns_add_txt_record() { + export _H1="Cookie:$1" + domain_id="$2" + subdomain="$3" + value="$(printf '%s' "$4" | _url_encode)" + url="http://freedns.afraid.org/subdomain/save.php?step=2" + + htmlpage="$(_post "type=TXT&domain_id=$domain_id&subdomain=$subdomain&address=%22$value%22&send=Save%21" "$url")" + + if [ "$?" != "0" ]; then + _err "FreeDNS failed to add TXT record for $subdomain bad RC from _post" + return 1 + fi + + if ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then + _debug "$htmlpage" + _err "FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file" + return 1 + fi + _info "Added acme challenge TXT record for $fulldomain at FreeDNS" + return 0 +} + +# usage _freedns_delete_txt_record login_cookies data_id +# returns 0 success +_freedns_delete_txt_record() { + export _H1="Cookie:$1" + data_id="$2" + url="https://freedns.afraid.org/subdomain/delete2.php" + + htmlheader="$(_get "$url?data_id%5B%5D=$data_id&submit=delete+selected" "onlyheader")" + + if [ "$?" != "0" ]; then + _err "FreeDNS failed to delete TXT record for $data_id bad RC from _get" + return 1 + fi + + if ! _contains "$htmlheader" "200 OK"; then + _debug "$htmlheader" + _err "FreeDNS failed to delete TXT record $data_id" + return 1 + fi + + _info "Deleted acme challenge TXT record for $fulldomain at FreeDNS" + return 0 +} + From 1476a9ecf144b3c5a033adc533b429fe1365e9a7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 1 Feb 2017 16:12:43 +0800 Subject: [PATCH 109/620] fix format --- dnsapi/dns_lua.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 42d55e84..828e8012 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -67,7 +67,7 @@ dns_lua_add() { _debug "record_id" "$record_id" _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":$record_id,\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":$_domain_id,\"ttl\":120}" - if [ "$?" = "0" ] && _contains "$response" "updated_at" ; then + if [ "$?" = "0" ] && _contains "$response" "updated_at"; then _info "Updated!" #todo: check if the record takes effect return 0 From 70b63a5ed442efe28587b8107c216db9e2965f70 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 1 Feb 2017 23:18:37 +0800 Subject: [PATCH 110/620] Create README.md --- deploy/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 deploy/README.md diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 00000000..580eaac8 --- /dev/null +++ b/deploy/README.md @@ -0,0 +1 @@ +#Using deploy api From 0aed065a75dc3be7c906a156ebad1b30344d09ba Mon Sep 17 00:00:00 2001 From: David Kerr Date: Wed, 1 Feb 2017 17:08:26 -0500 Subject: [PATCH 111/620] Updates to README.md --- README.md | 1 + dnsapi/README.md | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/README.md b/README.md index 90a64ee0..067e9b50 100644 --- a/README.md +++ b/README.md @@ -270,6 +270,7 @@ You don't have to do anything manually! 1. ISPConfig 3.1 API 1. Alwaysdata.com API 1. Linode.com API +1. FreeDNS **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index df728acc..9f06483e 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -278,6 +278,32 @@ acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.co The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +# 15. Use FreeDNS + +FreeDNS (https://freedns.afraid.org/) does not provide an API to update DNS records (other than IPv4 and IPv6 +dynamic DNS addresses). The acme.sh plugin therefore retrieves and updates domain TXT records by logging +into the FreeDNS website to read the HTML and posting updates as HTTP. The plugin needs to know your +userid and password for the FreeDNS website. + +```sh +export FREEDNS_User="..." +export FREEDNS_Password="..." +``` + +You need only provide this the first time you run the acme.sh client with FreeDNS validation and then again +whenever you change your password at the FreeDNS site. The acme.sh FreeDNS plugin does not store your userid +or password but rather saves an authentication token returned by FreeDNS in `~/.acme.sh/account.conf` and +reuses that when needed. + +Now you can issue a certificate. + +```sh +acme.sh --issue --dns dns_freedns --dnssleep 30 -d example.com -d www.example.com +``` + +FreeDNS updates records quite quickly so it is possible to reduce the dnssleep time, in the above example +to 30 seconds. + # Use custom API If your API is not supported yet, you can write your own DNS API. From 40e6ba1100e2ed61508131873fa99225748aded4 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Wed, 1 Feb 2017 17:12:52 -0500 Subject: [PATCH 112/620] fix heading level to match others. --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 9f06483e..65acb7d9 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -278,7 +278,7 @@ acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.co The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -# 15. Use FreeDNS +## 15. Use FreeDNS FreeDNS (https://freedns.afraid.org/) does not provide an API to update DNS records (other than IPv4 and IPv6 dynamic DNS addresses). The acme.sh plugin therefore retrieves and updates domain TXT records by logging From 6c4cc357b5ba12c5bd5682750647b198d40a8cdc Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 3 Feb 2017 11:13:38 +0800 Subject: [PATCH 113/620] _readlink --- acme.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 7ec84e6f..d4cbe1fd 100755 --- a/acme.sh +++ b/acme.sh @@ -1594,14 +1594,18 @@ _starttlsserver() { _readlink() { _rf="$1" if ! readlink -f "$_rf" 2>/dev/null; then - if _startswith "$_rf" "\./$PROJECT_ENTRY"; then - printf -- "%s" "$(pwd)/$PROJECT_ENTRY" + if _startswith "$_rf" "/"; then + echo "$_rf" return 0 fi - readlink "$_rf" + echo "$(pwd)/$_rf" | _conapath fi } +_conapath() { + sed "s#/\./#/#g" +} + __initHome() { if [ -z "$_SCRIPT_HOME" ]; then if _exists readlink && _exists dirname; then @@ -4440,7 +4444,7 @@ _process() { HTTPS_INSECURE="1" ;; --ca-bundle) - _ca_bundle="$(readlink -f "$2")" + _ca_bundle="$(_readlink -f "$2")" CA_BUNDLE="$_ca_bundle" shift ;; From 50a9680f17f0719450f3f1874d723d0db2c4a1fb Mon Sep 17 00:00:00 2001 From: David Kerr Date: Fri, 3 Feb 2017 11:13:12 -0500 Subject: [PATCH 114/620] Travis error... remove blank line at end of file. --- dnsapi/dns_freedns.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index ad3f9da3..28aaa77a 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -368,4 +368,3 @@ _freedns_delete_txt_record() { _info "Deleted acme challenge TXT record for $fulldomain at FreeDNS" return 0 } - From e6b940e24754ede06e8b2618d50347bf8f39185b Mon Sep 17 00:00:00 2001 From: David Kerr Date: Fri, 3 Feb 2017 22:59:22 -0500 Subject: [PATCH 115/620] Minor edits to FreeDNS documentation --- README.md | 2 +- dnsapi/README.md | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 067e9b50..c6362ed7 100644 --- a/README.md +++ b/README.md @@ -270,7 +270,7 @@ You don't have to do anything manually! 1. ISPConfig 3.1 API 1. Alwaysdata.com API 1. Linode.com API -1. FreeDNS +1. FreeDNS (https://freedns.afraid.org/) **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 65acb7d9..fc613e2a 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -278,7 +278,7 @@ acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.co The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -## 15. Use FreeDNS +## 15. Use FreeDNS FreeDNS (https://freedns.afraid.org/) does not provide an API to update DNS records (other than IPv4 and IPv6 dynamic DNS addresses). The acme.sh plugin therefore retrieves and updates domain TXT records by logging @@ -298,12 +298,9 @@ reuses that when needed. Now you can issue a certificate. ```sh -acme.sh --issue --dns dns_freedns --dnssleep 30 -d example.com -d www.example.com +acme.sh --issue --dns dns_freedns -d example.com -d www.example.com ``` -FreeDNS updates records quite quickly so it is possible to reduce the dnssleep time, in the above example -to 30 seconds. - # Use custom API If your API is not supported yet, you can write your own DNS API. From f78b656f5f6c20bde86c10b1bfb40bf2f210d899 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sat, 4 Feb 2017 10:21:58 -0500 Subject: [PATCH 116/620] Add error message if fails to add TXT record for missing security code (probably a FreeDNS public domain) --- dnsapi/README.md | 4 ++++ dnsapi/dns_freedns.sh | 19 ++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index fc613e2a..6a86bf4c 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -301,6 +301,10 @@ Now you can issue a certificate. acme.sh --issue --dns dns_freedns -d example.com -d www.example.com ``` +Note that you cannot use acme.sh automatic DNS validation for FreeDNS public domains or for a subdomain that +you create under a FreeDNS public domain. You must own the top level domain in order to automaitcally +validate with acme.sh at FreeDNS. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 28aaa77a..8d519fd5 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -307,9 +307,7 @@ _freedns_retrieve_subdomain_page() { if [ "$?" != "0" ]; then _err "FreeDNS retrieve subdomins failed bad RC from _get" return 1 - fi - - if [ -z "$htmlpage" ]; then + elif [ -z "$htmlpage" ]; then _err "FreeDNS returned empty subdomain page" return 1 fi @@ -334,13 +332,18 @@ _freedns_add_txt_record() { if [ "$?" != "0" ]; then _err "FreeDNS failed to add TXT record for $subdomain bad RC from _post" return 1 - fi - - if ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then + elif ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then _debug "$htmlpage" _err "FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file" return 1 + elif _contains "$htmlpage" "security code was incorrect"; then + _debug "$htmlpage" + _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested seurity code" + _err "Note that you cannot use automatic DNS validation for FreeDNS public domains" + return 1 fi + + _debug2 "$htmlpage" _info "Added acme challenge TXT record for $fulldomain at FreeDNS" return 0 } @@ -357,9 +360,7 @@ _freedns_delete_txt_record() { if [ "$?" != "0" ]; then _err "FreeDNS failed to delete TXT record for $data_id bad RC from _get" return 1 - fi - - if ! _contains "$htmlheader" "200 OK"; then + elif ! _contains "$htmlheader" "200 OK"; then _debug "$htmlheader" _err "FreeDNS failed to delete TXT record $data_id" return 1 From 87f5ec5be52208c2daaf040c646bee69fdcb7771 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Sat, 4 Feb 2017 10:36:51 -0500 Subject: [PATCH 117/620] Add Accept-Language:en-US to HTTP header as precaution against future multi-lingual FreeDNS pages. --- dnsapi/dns_freedns.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 8d519fd5..f30c8958 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -267,6 +267,7 @@ dns_freedns_rm() { # print string "cookie=value" etc. # returns 0 success _freedns_login() { + export _H1="Accept-Language:en-US" username="$1" password="$2" url="https://freedns.afraid.org/zc.php?step=2" @@ -298,6 +299,7 @@ _freedns_login() { # returns 0 success _freedns_retrieve_subdomain_page() { export _H1="Cookie:$1" + export _H2="Accept-Language:en-US" url="https://freedns.afraid.org/subdomain/" _debug "Retrieve subdmoain page from FreeDNS" @@ -322,6 +324,7 @@ _freedns_retrieve_subdomain_page() { # returns 0 success _freedns_add_txt_record() { export _H1="Cookie:$1" + export _H2="Accept-Language:en-US" domain_id="$2" subdomain="$3" value="$(printf '%s' "$4" | _url_encode)" @@ -352,6 +355,7 @@ _freedns_add_txt_record() { # returns 0 success _freedns_delete_txt_record() { export _H1="Cookie:$1" + export _H2="Accept-Language:en-US" data_id="$2" url="https://freedns.afraid.org/subdomain/delete2.php" From 9bdb799b412bf86cddbe62d630e94a023fcc532d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 5 Feb 2017 13:16:51 +0800 Subject: [PATCH 118/620] fix bug when the od command is missing --- acme.sh | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index bc211522..df4a0b4a 100755 --- a/acme.sh +++ b/acme.sh @@ -340,11 +340,29 @@ _is_solaris() { _contains "${__OS__:=$(uname -a)}" "solaris" || _contains "${__OS__:=$(uname -a)}" "SunOS" } +#_ascii_hex str +#this can only process ascii chars, should only be used when od command is missing as a backup way. +_ascii_hex() { + _debug2 "Using _ascii_hex" + _str="$1" + _str_len=${#_str} + _h_i=1 + while [ "$_h_i" -le "$_str_len" ]; do + _str_c="$(printf "%s" "$_str" | cut -c "$_h_i")" + printf " %02x" "'$_str_c" + _h_i="$(_math "$_h_i" + 1)" + done +} + #stdin output hexstr splited by one space #input:"abc" #output: " 61 62 63" _hex_dump() { - od -A n -v -t x1 | tr -d "\r\t" | tr -s " " | sed "s/ $//" | tr -d "\n" + #in wired some system, the od command is missing. + if ! od -A n -v -t x1 | tr -d "\r\t" | tr -s " " | sed "s/ $//" | tr -d "\n" 2>/dev/null; then + str=$(cat) + _ascii_hex "$str" + fi } #url encode, no-preserved chars From b22b085b508c745030b9ecd4ce931fca19f43455 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 5 Feb 2017 22:08:52 +0800 Subject: [PATCH 119/620] fix https://github.com/Neilpang/acme.sh/issues/578 support openssl 1.1.0 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index df4a0b4a..ec41b60f 100755 --- a/acme.sh +++ b/acme.sh @@ -914,7 +914,7 @@ _readSubjectFromCSR() { _usage "_readSubjectFromCSR mycsr.csr" return 1 fi - $OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' + $OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' } #_csrfile From 562a4c056ea208e85e6f0551a188d55cee8050d5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 5 Feb 2017 23:06:06 +0800 Subject: [PATCH 120/620] add note info if netcat-openbsd is required. --- acme.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/acme.sh b/acme.sh index ec41b60f..b22b2e69 100755 --- a/acme.sh +++ b/acme.sh @@ -61,6 +61,8 @@ DEFAULT_LOG_LEVEL="$LOG_LEVEL_1" _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" + __INTERACTIVE="" if [ -t 1 ]; then __INTERACTIVE="1" @@ -1684,6 +1686,14 @@ _startserver() { _NC="$_NC -6" fi + if [ "$Le_Listen_V4$Le_Listen_V6$ncaddr" ]; then + if ! _contains "$nchelp" "OpenBSD"; then + _err "The nc doesn't support '-4', '-6' or local-address, please install 'netcat-openbsd' and try again." + _err "See $(__green $_PREPARE_LINK)" + return 1 + fi + fi + if echo "$nchelp" | grep "\-q[ ,]" >/dev/null; then _NC="$_NC -q 1 -l $ncaddr" else From b4325026b17374efdbcc7726369085e4373f23ef Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 5 Feb 2017 23:14:25 +0800 Subject: [PATCH 121/620] exe --- deploy/kong.sh | 0 deploy/myapi.sh | 0 dnsapi/dns_ad.sh | 0 dnsapi/dns_ali.sh | 0 dnsapi/dns_aws.sh | 0 5 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 deploy/kong.sh mode change 100644 => 100755 deploy/myapi.sh mode change 100644 => 100755 dnsapi/dns_ad.sh mode change 100644 => 100755 dnsapi/dns_ali.sh mode change 100644 => 100755 dnsapi/dns_aws.sh diff --git a/deploy/kong.sh b/deploy/kong.sh old mode 100644 new mode 100755 diff --git a/deploy/myapi.sh b/deploy/myapi.sh old mode 100644 new mode 100755 diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh old mode 100644 new mode 100755 diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh old mode 100644 new mode 100755 diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh old mode 100644 new mode 100755 From 0ca5b7996cddab0e471efcb25313c3d6301cdfb1 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 6 Feb 2017 09:28:30 +0800 Subject: [PATCH 122/620] minor clear account conf --- acme.sh | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index b22b2e69..08e06fbd 100755 --- a/acme.sh +++ b/acme.sh @@ -3906,12 +3906,7 @@ _detect_profile() { _initconf() { _initpath if [ ! -f "$ACCOUNT_CONF_PATH" ]; then - echo "#ACCOUNT_CONF_PATH=xxxx - -#ACCOUNT_EMAIL=aaa@example.com # the account email used to register account. -#ACCOUNT_KEY_PATH=\"/path/to/account.key\" -#CERT_HOME=\"/path/to/cert/home\" - + echo " #LOG_FILE=\"$DEFAULT_LOG_FILE\" #LOG_LEVEL=1 @@ -3919,12 +3914,6 @@ _initconf() { #AUTO_UPGRADE=\"1\" #NO_TIMESTAMP=1 -#OPENSSL_BIN=openssl - -#USER_AGENT=\"$USER_AGENT\" - -#USER_PATH= - " >"$ACCOUNT_CONF_PATH" fi From dba26c3240efaa6cdd9c6f163f8294242c2bdbfd Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 6 Feb 2017 13:27:58 +0800 Subject: [PATCH 123/620] fix check for Mac nc command, it doesn't contain "openbsd", but it works. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 08e06fbd..d3d46b59 100755 --- a/acme.sh +++ b/acme.sh @@ -1687,7 +1687,7 @@ _startserver() { fi if [ "$Le_Listen_V4$Le_Listen_V6$ncaddr" ]; then - if ! _contains "$nchelp" "OpenBSD"; then + if ! _contains "$nchelp" "-4"; then _err "The nc doesn't support '-4', '-6' or local-address, please install 'netcat-openbsd' and try again." _err "See $(__green $_PREPARE_LINK)" return 1 From d6edff3182e3e3fe672652aa02324590e7f2057d Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 6 Feb 2017 14:20:37 +0800 Subject: [PATCH 124/620] fix ci --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8d6d30ad..1d54faed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,6 @@ install: fi script: - - echo "TEST_LOCAL=$TEST_LOCAL" - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - command -V openssl && openssl version - if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi @@ -44,8 +43,8 @@ script: - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck **/*.sh && echo "shellcheck OK" ; fi - cd .. - git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest - - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi - - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi + - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi matrix: From 5d2c5b01a80c2cdc555673926e7b865e33297ddd Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 6 Feb 2017 19:30:53 +0800 Subject: [PATCH 125/620] add _utc_date function --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index d3d46b59..0b234953 100755 --- a/acme.sh +++ b/acme.sh @@ -1265,6 +1265,10 @@ _time() { date -u "+%s" } +_utc_date() { + date -u "+%Y-%m-%d %H:%M:%S" +} + _mktemp() { if _exists mktemp; then if mktemp 2>/dev/null; then From 339a8ad61041591d6cc2bb3af77ed855e13e735d Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 6 Feb 2017 19:53:12 +0800 Subject: [PATCH 126/620] minor, output thumbprint --- acme.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 0b234953..7ad5897d 100755 --- a/acme.sh +++ b/acme.sh @@ -2489,6 +2489,10 @@ __calcAccountKeyHash() { [ -f "$ACCOUNT_KEY_PATH" ] && _digest sha256 <"$ACCOUNT_KEY_PATH" } +__calc_account_thumbprint() { + printf "%s" "$jwk" | tr -d ' ' | _digest "sha256" | _url_replace +} + #keylength _regAccount() { _initpath @@ -2579,6 +2583,8 @@ _regAccount() { return 1 fi fi + ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)" + _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT" return 0 done @@ -2810,8 +2816,7 @@ issue() { fi if [ -z "$thumbprint" ]; then - accountkey_json=$(printf "%s" "$jwk" | tr -d ' ') - thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _url_replace) + thumbprint="$(__calc_account_thumbprint)" fi entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" From 0e44f587a5052ece05ad09674c0384809c95dd7e Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 6 Feb 2017 20:42:54 +0800 Subject: [PATCH 127/620] add stateless mode --- acme.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 7ad5897d..cb99b5ab 100755 --- a/acme.sh +++ b/acme.sh @@ -41,6 +41,8 @@ NO_VALUE="no" W_TLS="tls" +MODE_STATELESS="stateless" + STATE_VERIFIED="verified_ok" BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" @@ -63,6 +65,8 @@ _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" +_STATELESS_WIKI="https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode" + __INTERACTIVE="" if [ -t 1 ]; then __INTERACTIVE="1" @@ -2973,7 +2977,9 @@ issue() { serverproc="$!" sleep 1 _debug serverproc "$serverproc" - + elif [ "$_currentRoot" = "$MODE_STATELESS" ]; then + _info "Stateless mode for domain:$d" + _sleep 1 else if [ "$_currentRoot" = "apache" ]; then wellknown_path="$ACME_DIR" @@ -4258,6 +4264,7 @@ Parameters: --webroot, -w /path/to/webroot Specifies the web root folder for web root mode. --standalone Use standalone mode. + --stateless Use stateless mode, see: $_STATELESS_WIKI --tls Use standalone tls mode. --apache Use apache mode. --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api. @@ -4563,6 +4570,14 @@ _process() { _webroot="$_webroot,$wvalue" fi ;; + --stateless) + wvalue="$MODE_STATELESS" + if [ -z "$_webroot" ]; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; --local-address) lvalue="$2" _local_address="$_local_address$lvalue," From 7c488b5913f47aecfcc61d8e6d329a4b374387c3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 6 Feb 2017 21:37:21 +0800 Subject: [PATCH 128/620] doc for stateless mode --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c6362ed7..2dd178d8 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ https://github.com/Neilpang/acmetest - Standalone mode - Apache mode - DNS mode +- [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode) # 1. How to install From c9d7daab70476e7c5f60a4e0aea06c671d91cb3d Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 10 Feb 2017 13:34:34 +0800 Subject: [PATCH 129/620] fix https://github.com/Neilpang/acme.sh/issues/593 --- 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 555bd70b..29d7a2cd 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -93,7 +93,7 @@ _get_root() { fi if _contains "$response" "$h."; then - hostedzone="$(echo "$response" | _egrep_o "[^<]*<.Id>$h.<.Name>.*<.HostedZone>")" + hostedzone="$(echo "$response" | sed 's//#&/g' | tr '#' '\n' | _egrep_o "[^<]*<.Id>$h.<.Name>.*<.HostedZone>")" _debug hostedzone "$hostedzone" if [ -z "$hostedzone" ]; then _err "Error, can not get hostedzone." From 34f25fa590ba9917ecfd8f70887635ed5d2c467d Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 10 Feb 2017 18:20:15 +0800 Subject: [PATCH 130/620] support mingw/git-bash --- acme.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index cb99b5ab..4279ddfc 100755 --- a/acme.sh +++ b/acme.sh @@ -896,7 +896,11 @@ _createcsr() { _csr_cn="$(_idn "$domain")" _debug2 _csr_cn "$_csr_cn" - $OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" + if _contains "$(uname -a)" "MINGW"; then + $OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" + else + $OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" + fi } #_signcsr key csr conf cert From d8beaf727f84ac8149e290b5695dc35634e195e2 Mon Sep 17 00:00:00 2001 From: hebbet Date: Fri, 10 Feb 2017 13:26:17 +0100 Subject: [PATCH 131/620] remove extra space remove extra space from help --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4279ddfc..8eb52d3e 100755 --- a/acme.sh +++ b/acme.sh @@ -4238,7 +4238,7 @@ Commands: --version, -v Show version info. --install Install $PROJECT_NAME to your system. --uninstall Uninstall $PROJECT_NAME, and uninstall the cron job. - --upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT . + --upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT. --issue Issue a cert. --signcsr Issue a cert from an existing csr. --deploy Deploy the cert to your server. From 4e4a6d83973fa0580ef8b2f1d7d0312fdd671543 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 10 Feb 2017 20:55:25 +0800 Subject: [PATCH 132/620] better hexdump fix https://github.com/Neilpang/acme.sh/issues/595 --- acme.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 4279ddfc..b544f531 100755 --- a/acme.sh +++ b/acme.sh @@ -364,8 +364,16 @@ _ascii_hex() { #input:"abc" #output: " 61 62 63" _hex_dump() { - #in wired some system, the od command is missing. - if ! od -A n -v -t x1 | tr -d "\r\t" | tr -s " " | sed "s/ $//" | tr -d "\n" 2>/dev/null; then + if _exists od; then + od -A n -v -t x1 | tr -s " " | sed 's/ $//' | tr -d "\r\t\n" + elif _exists hexdump; then + _debug3 "using hexdump" + hexdump -v -e '/1 ""' -e '/1 " %02x" ""' + elif _exists xxd; then + _debug3 "using xxd" + xxd -ps -c 20 -i | sed "s/ 0x/ /g" | tr -d ",\n" | tr -s " " + else + _debug3 "using _ascii_hex" str=$(cat) _ascii_hex "$str" fi From 04e0f87c0387e81b100f94de9a511e47f0b49f75 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 11 Feb 2017 13:24:00 +0800 Subject: [PATCH 133/620] add doc --- deploy/README.md | 31 ++++++++++++++++++++++++++++++- deploy/cpanel.sh | 29 +++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 deploy/cpanel.sh diff --git a/deploy/README.md b/deploy/README.md index 580eaac8..fcdf8019 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -1 +1,30 @@ -#Using deploy api +# Using deploy api + +Here are the scripts to deploy the certs/key to the server/services. + +## 1. Deploy the certs to your cpanel host. + +(cpanel deploy hook is not finished yet, this is just an example.) + +Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). + +Then you can deploy now: + +```sh +export DEPLOY_CPANEL_USER=myusername +export DEPLOY_CPANEL_PASSWORD=PASSWORD +acme.sh --deploy -d example.com --deploy --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). + +(TODO) + +## 3. Deploy the cert to remote server through SSH access. + +(TODO) + + + diff --git a/deploy/cpanel.sh b/deploy/cpanel.sh new file mode 100644 index 00000000..bf1332ff --- /dev/null +++ b/deploy/cpanel.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env sh + +#Here is the script to deploy the cert to your cpanel account by the cpanel APIs. + +#returns 0 means success, otherwise error. + +#export DEPLOY_CPANEL_USER=myusername +#export DEPLOY_CPANEL_PASSWORD=PASSWORD + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +cpanel_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "Not implemented yet" + return 1 + +} From 0984585d58cc87a8b49ee93ad8d5c6924c88a79d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 11 Feb 2017 13:36:52 +0800 Subject: [PATCH 134/620] minor, rename command --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 04bf55ad..67c72068 100755 --- a/acme.sh +++ b/acme.sh @@ -4263,8 +4263,8 @@ Commands: --toPkcs Export the certificate and key to a pfx file. --update-account Update account info. --register-account Register account key. - --createAccountKey, -cak Create an account private key, professional use. - --createDomainKey, -cdk Create an domain private key, professional use. + --create-account-key Create an account private key, professional use. + --create-domain-key Create an domain private key, professional use. --createCSR, -ccsr Create CSR , professional use. --deactivate Deactivate the domain authz, professional use. @@ -4506,10 +4506,10 @@ _process() { --toPkcs) _CMD="toPkcs" ;; - --createAccountKey | --createaccountkey | -cak) + --createAccountKey | --createaccountkey | -cak | --create-account-key) _CMD="createAccountKey" ;; - --createDomainKey | --createdomainkey | -cdk) + --createDomainKey | --createdomainkey | -cdk | --create-domain-key) _CMD="createDomainKey" ;; --createCSR | --createcsr | -ccr) From d47c5eaf604743867ae0ca2fdeda0d2108747c4e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 11 Feb 2017 20:13:21 +0800 Subject: [PATCH 135/620] update issue template --- .github/ISSUE_TEMPLATE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 4abbb7ab..f7d4d1d7 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,4 +1,6 @@ Steps to reproduce ------------------ - Debug log ----------------- From e2edf2083384f6ceae71d89e569052b1ba3b827d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 11 Feb 2017 21:15:36 +0800 Subject: [PATCH 136/620] support syslog --- acme.sh | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index 67c72068..9929dfad 100755 --- a/acme.sh +++ b/acme.sh @@ -61,6 +61,10 @@ LOG_LEVEL_2=2 LOG_LEVEL_3=3 DEFAULT_LOG_LEVEL="$LOG_LEVEL_1" +SYSLOG_INFO="user.info" +SYSLOG_ERROR="user.error" +SYSLOG_DEBUG="user.debug" + _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" @@ -128,18 +132,30 @@ _dlg_versions() { fi } +#class +_syslog() { + if [ -z "$SYS_LOG" ] || [ "$SYS_LOG" = "0" ]; then + return + fi + _logclass="$1" + shift + logger -i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1 +} + _log() { + _syslog "$@" [ -z "$LOG_FILE" ] && return + shift _printargs "$@" >>"$LOG_FILE" } _info() { - _log "$@" + _log "$SYSLOG_INFO" "$@" _printargs "$@" } _err() { - _log "$@" + _log "$SYSLOG_ERROR" "$@" if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then printf -- "%s" "[$(date)] " >&2 fi @@ -159,7 +175,7 @@ _usage() { _debug() { if [ -z "$LOG_LEVEL" ] || [ "$LOG_LEVEL" -ge "$LOG_LEVEL_1" ]; then - _log "$@" + _log "$SYSLOG_DEBUG" "$@" fi if [ -z "$DEBUG" ]; then return @@ -169,19 +185,19 @@ _debug() { _debug2() { if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_2" ]; then - _log "$@" + _log "$SYSLOG_DEBUG" "$@" fi if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - _debug "$@" + _printargs "$@" >&2 fi } _debug3() { if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_3" ]; then - _log "$@" + _log "$SYSLOG_DEBUG" "$@" fi if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ]; then - _debug "$@" + _printargs "$@" >&2 fi } @@ -4286,6 +4302,7 @@ Parameters: --accountkeylength, -ak [2048] Specifies the account key length. --log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here. --log-level 1|2 Specifies the log level, default is 1. + --syslog [1|0] Enable/Disable syslog. These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: @@ -4444,6 +4461,7 @@ _process() { _listen_v4="" _listen_v6="" _openssl_bin="" + _syslog="" while [ ${#} -gt 0 ]; do case "${1}" in @@ -4774,6 +4792,15 @@ _process() { LOG_LEVEL="$_log_level" shift ;; + --syslog) + if ! _startswith "$2" '-'; then + _syslog="$2" + shift + fi + if [ -z "$_syslog" ]; then + _syslog="1" + fi + ;; --auto-upgrade) _auto_upgrade="$2" if [ -z "$_auto_upgrade" ] || _startswith "$_auto_upgrade" '-'; then @@ -4821,6 +4848,21 @@ _process() { LOG_LEVEL="$_log_level" fi + if [ "$_syslog" ]; then + if _exists logger; then + if [ "$_syslog" = "0" ]; then + _clearaccountconf "SYS_LOG" + else + _saveaccountconf "SYS_LOG" "$_syslog" + fi + SYS_LOG="$_syslog" + else + _err "The 'logger' command is not found, can not enable syslog." + _clearaccountconf "SYS_LOG" + SYS_LOG="" + fi + fi + _processAccountConf fi @@ -4913,6 +4955,21 @@ _process() { if [ "$_log_level" ]; then _saveaccountconf "LOG_LEVEL" "$_log_level" fi + + if [ "$_syslog" ]; then + if _exists logger; then + if [ "$_syslog" = "0" ]; then + _clearaccountconf "SYS_LOG" + else + _saveaccountconf "SYS_LOG" "$_syslog" + fi + else + _err "The 'logger' command is not found, can not enable syslog." + _clearaccountconf "SYS_LOG" + SYS_LOG="" + fi + fi + _processAccountConf fi From cd9c3a79e556c6221d3fe15aaa4dc3f50689bc98 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 11 Feb 2017 21:29:36 +0800 Subject: [PATCH 137/620] update doc --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2dd178d8..f1c74806 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ You **MUST** use this command to copy the certs to the target files, **DO NOT** **Apache** example: ```bash -acme.sh --installcert -d example.com \ +acme.sh --install-cert -d example.com \ --certpath /path/to/certfile/in/apache/cert.pem \ --keypath /path/to/keyfile/in/apache/key.pem \ --fullchainpath /path/to/fullchain/certfile/apache/fullchain.pem \ @@ -156,7 +156,7 @@ acme.sh --installcert -d example.com \ **Nginx** example: ```bash -acme.sh --installcert -d example.com \ +acme.sh --install-cert -d example.com \ --keypath /path/to/keyfile/in/nginx/key.pem \ --fullchainpath /path/to/fullchain/nginx/cert.pem \ --reloadcmd "service nginx force-reload" From fd72cced13e37c3a5f877e14825bac2d6c455a2a Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 12 Feb 2017 10:10:53 +0800 Subject: [PATCH 138/620] move the backup file to acme home fix https://github.com/Neilpang/acme.sh/issues/488 --- acme.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 9929dfad..5ce5b803 100755 --- a/acme.sh +++ b/acme.sh @@ -2059,6 +2059,10 @@ _initpath() { _debug DOMAIN_PATH "$DOMAIN_PATH" fi + if [ -z "$DOMAIN_BACKUP_PATH" ]; then + DOMAIN_BACKUP_PATH="$DOMAIN_PATH" + fi + if [ -z "$DOMAIN_CONF" ]; then DOMAIN_CONF="$DOMAIN_PATH/$domain.conf" fi @@ -3612,7 +3616,7 @@ _installcert() { _info "Installing cert to:$Le_RealCertPath" if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ]; then - cp "$Le_RealCertPath" "$Le_RealCertPath".bak + cp "$Le_RealCertPath" "$DOMAIN_BACKUP_PATH/cert.bak" fi cat "$CERT_PATH" >"$Le_RealCertPath" fi @@ -3625,7 +3629,7 @@ _installcert() { cat "$CA_CERT_PATH" >>"$Le_RealCACertPath" else if [ -f "$Le_RealCACertPath" ] && [ ! "$IS_RENEW" ]; then - cp "$Le_RealCACertPath" "$Le_RealCACertPath".bak + cp "$Le_RealCACertPath" "$DOMAIN_BACKUP_PATH/ca.bak" fi cat "$CA_CERT_PATH" >"$Le_RealCACertPath" fi @@ -3635,7 +3639,7 @@ _installcert() { _info "Installing key to:$Le_RealKeyPath" if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ]; then - cp "$Le_RealKeyPath" "$Le_RealKeyPath".bak + cp "$Le_RealKeyPath" "$DOMAIN_BACKUP_PATH/key.bak" fi cat "$CERT_KEY_PATH" >"$Le_RealKeyPath" fi @@ -3644,7 +3648,7 @@ _installcert() { _info "Installing full chain to:$Le_RealFullChainPath" if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ]; then - cp "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak + cp "$Le_RealFullChainPath" "$DOMAIN_BACKUP_PATH/fullchain.bak" fi cat "$CERT_FULLCHAIN_PATH" >"$Le_RealFullChainPath" fi From d88f8e862bc33d4d989be7acb1e1f05049e0163f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 12 Feb 2017 10:20:50 +0800 Subject: [PATCH 139/620] move backup to sub folder. --- acme.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5ce5b803..f03501b4 100755 --- a/acme.sh +++ b/acme.sh @@ -2060,7 +2060,7 @@ _initpath() { fi if [ -z "$DOMAIN_BACKUP_PATH" ]; then - DOMAIN_BACKUP_PATH="$DOMAIN_PATH" + DOMAIN_BACKUP_PATH="$DOMAIN_PATH/backup" fi if [ -z "$DOMAIN_CONF" ]; then @@ -3616,6 +3616,7 @@ _installcert() { _info "Installing cert to:$Le_RealCertPath" if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ]; then + mkdir -p "$DOMAIN_BACKUP_PATH" cp "$Le_RealCertPath" "$DOMAIN_BACKUP_PATH/cert.bak" fi cat "$CERT_PATH" >"$Le_RealCertPath" @@ -3629,6 +3630,7 @@ _installcert() { cat "$CA_CERT_PATH" >>"$Le_RealCACertPath" else if [ -f "$Le_RealCACertPath" ] && [ ! "$IS_RENEW" ]; then + mkdir -p "$DOMAIN_BACKUP_PATH" cp "$Le_RealCACertPath" "$DOMAIN_BACKUP_PATH/ca.bak" fi cat "$CA_CERT_PATH" >"$Le_RealCACertPath" @@ -3639,6 +3641,7 @@ _installcert() { _info "Installing key to:$Le_RealKeyPath" if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ]; then + mkdir -p "$DOMAIN_BACKUP_PATH" cp "$Le_RealKeyPath" "$DOMAIN_BACKUP_PATH/key.bak" fi cat "$CERT_KEY_PATH" >"$Le_RealKeyPath" @@ -3648,6 +3651,7 @@ _installcert() { _info "Installing full chain to:$Le_RealFullChainPath" if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ]; then + mkdir -p "$DOMAIN_BACKUP_PATH" cp "$Le_RealFullChainPath" "$DOMAIN_BACKUP_PATH/fullchain.bak" fi cat "$CERT_FULLCHAIN_PATH" >"$Le_RealFullChainPath" From 0ec9b9823f3ff32108bab78f5e2b5f1c0750adf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 22 Nov 2016 00:24:26 +0100 Subject: [PATCH 140/620] Add DNS API for cyon.ch --- dnsapi/dns_cyon.sh | 355 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) create mode 100644 dnsapi/dns_cyon.sh diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh new file mode 100644 index 00000000..95e690bb --- /dev/null +++ b/dnsapi/dns_cyon.sh @@ -0,0 +1,355 @@ +#!/usr/bin/env sh + +######## +# Custom cyon.ch DNS API for use with [acme.sh](https://github.com/Neilpang/acme.sh) +# +# Usage: acme.sh --issue --dns dns_cyon -d www.domain.com +# +# Dependencies: +# ------------- +# - jq (get it here: https://stedolan.github.io/jq/download) +# - oathtool (When using 2 Factor Authentication) +# +# Author: Armando Lüscher +######## + +######## +# Define cyon.ch login credentials: +# +# Either set them here: (uncomment these lines) +# +# cyon_username='your_cyon_username' +# cyon_password='your_cyon_password' +# cyon_otp_secret='your_otp_secret' # Only required if using 2FA +# +# ...or export them as environment variables in your shell: +# +# $ export cyon_username='your_cyon_username' +# $ export cyon_password='your_cyon_password' +# $ export cyon_otp_secret='your_otp_secret' # Only required if using 2FA +# +# *Note:* +# After the first run, the credentials are saved in the "account.conf" +# file, so any hard-coded or environment variables can then be removed. +######## + +dns_cyon_add() { + if ! _exists jq; then + _fail "Please install jq to use cyon.ch DNS API." + fi + + _load_credentials + _load_parameters "$@" + + _info_header "add" + _login + _domain_env + _add_txt + _cleanup + + return 0 +} + +dns_cyon_rm() { + _load_credentials + _load_parameters "$@" + + _info_header "delete" + _login + _domain_env + _delete_txt + _cleanup + + return 0 +} + +######################### +### PRIVATE FUNCTIONS ### +######################### + +_load_credentials() { + # Convert loaded password to/from base64 as needed. + if [ "${cyon_password_b64}" ] ; then + cyon_password="$(echo "${cyon_password_b64}" | _dbase64)" + elif [ "${cyon_password}" ] ; then + cyon_password_b64="$(echo "${cyon_password}" | _base64)" + fi + + if [ -z "${cyon_username}" ] || [ -z "${cyon_password}" ] ; then + _err "" + _err "You haven't set your cyon.ch login credentials yet." + _err "Please set the required cyon environment variables." + _err "" + exit 1 + fi + + # Save the login credentials to the account.conf file. + _debug "Save credentials to account.conf" + _saveaccountconf cyon_username "${cyon_username}" + _saveaccountconf cyon_password_b64 "$cyon_password_b64" + if [ ! -z "${cyon_otp_secret}" ] ; then + _saveaccountconf cyon_otp_secret "$cyon_otp_secret" + fi +} + +_is_idn() { + _idn_temp=$(printf "%s" "$1" | tr -d "[0-9a-zA-Z.,-]") + _idn_temp2="$(printf "%s" "$1" | grep -o "xn--")" + [ "$_idn_temp" ] || [ "$_idn_temp2" ] +} + +_load_parameters() { + # Read the required parameters to add the TXT entry. + fulldomain="$(echo "$1" | tr '[:upper:]' '[:lower:]')" + fulldomain_idn="${fulldomain}" + + # Special case for IDNs, as cyon needs a domain environment change, + # which uses the "pretty" instead of the punycode version. + if _is_idn "$1" ; then + if ! _exists idn; then + _fail "Please install idn to process IDN names." + fi + + fulldomain="$(idn -u "${fulldomain}")" + fulldomain_idn="$(idn -a "${fulldomain}")" + fi + + _debug fulldomain "$fulldomain" + _debug fulldomain_idn "$fulldomain_idn" + + txtvalue="$2" + _debug txtvalue "$txtvalue" + + # Cookiejar required for login session, as cyon.ch has no official API (yet). + cookiejar=$(tempfile) + _debug cookiejar "$cookiejar" +} + +_info_header() { + if [ "$1" = "add" ]; then + _info "" + _info "+---------------------------------------------+" + _info "| Adding DNS TXT entry to your cyon.ch domain |" + _info "+---------------------------------------------+" + _info "" + _info " * Full Domain: ${fulldomain}" + _info " * TXT Value: ${txtvalue}" + _info " * Cookie Jar: ${cookiejar}" + _info "" + elif [ "$1" = "delete" ]; then + _info "" + _info "+-------------------------------------------------+" + _info "| Deleting DNS TXT entry from your cyon.ch domain |" + _info "+-------------------------------------------------+" + _info "" + _info " * Full Domain: ${fulldomain}" + _info " * Cookie Jar: ${cookiejar}" + _info "" + fi +} + +_login() { + _info " - Logging in..." + login_response=$(curl \ + "https://my.cyon.ch/auth/index/dologin-async" \ + -s \ + -c "${cookiejar}" \ + -H "X-Requested-With: XMLHttpRequest" \ + --data-urlencode "username=${cyon_username}" \ + --data-urlencode "password=${cyon_password}" \ + --data-urlencode "pathname=/") + + _debug login_response "${login_response}" + + # Bail if login fails. + if [ "$(echo "${login_response}" | jq -r '.onSuccess')" != "success" ]; then + _fail " $(echo "${login_response}" | jq -r '.message')" + fi + + _info " success" + + + # NECESSARY!! Load the main page after login, before the OTP check. + curl "https://my.cyon.ch/" -s --compressed -b "${cookiejar}" >/dev/null + + + # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. + + + # 2FA authentication with OTP? + if [ ! -z "${cyon_otp_secret}" ] ; then + _info " - Authorising with OTP code..." + + if ! _exists oathtool; then + _fail "Please install oathtool to use 2 Factor Authentication." + fi + + # Get OTP code with the defined secret. + otp_code=$(oathtool --base32 --totp "${cyon_otp_secret}" 2>/dev/null) + + otp_response=$(curl \ + "https://my.cyon.ch/auth/multi-factor/domultifactorauth-async" \ + -s \ + --compressed \ + -b "${cookiejar}" \ + -c "${cookiejar}" \ + -H "X-Requested-With: XMLHttpRequest" \ + -d "totpcode=${otp_code}&pathname=%2F&rememberme=0") + + _debug otp_response "${otp_response}" + + # Bail if OTP authentication fails. + if [ "$(echo "${otp_response}" | jq -r '.onSuccess')" != "success" ]; then + _fail " $(echo "${otp_response}" | jq -r '.message')" + fi + + _info " success" + fi + + _info "" +} + +_domain_env() { + _info " - Changing domain environment..." + + # Get the "example.com" part of the full domain name. + domain_env=$(echo "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/') + _debug "Changing domain environment to ${domain_env}" + + domain_env_response=$(curl \ + "https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/domain%3A${domain_env}" \ + -s \ + --compressed \ + -b "${cookiejar}" \ + -H "X-Requested-With: XMLHttpRequest") + + _debug domain_env_response "${domain_env_response}" + + _check_2fa_miss "${domain_env_response}" + + domain_env_success=$(echo "${domain_env_response}" | jq -r '.authenticated') + + # Bail if domain environment change fails. + if [ "${domain_env_success}" != "true" ]; then + _fail " $(echo "${domain_env_response}" | jq -r '.message')" + fi + + _info " success" + _info "" +} + +_add_txt() { + _info " - Adding DNS TXT entry..." + addtxt_response=$(curl \ + "https://my.cyon.ch/domain/dnseditor/add-record-async" \ + -s \ + --compressed \ + -b "${cookiejar}" \ + -H "X-Requested-With: XMLHttpRequest" \ + -d "zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}") + + _debug addtxt_response "${addtxt_response}" + + _check_2fa_miss "${addtxt_response}" + + addtxt_message=$(echo "${addtxt_response}" | jq -r '.message') + addtxt_status=$(echo "${addtxt_response}" | jq -r '.status') + + # Bail if adding TXT entry fails. + if [ "${addtxt_status}" != "true" ]; then + if [ "${addtxt_status}" = "null" ]; then + addtxt_message=$(echo "${addtxt_response}" | jq -r '.error.message') + fi + _fail " ${addtxt_message}" + fi + + _info " success" + _info "" +} + +_delete_txt() { + _info " - Deleting DNS TXT entry..." + + list_txt_response=$(curl \ + "https://my.cyon.ch/domain/dnseditor/list-async" \ + -s \ + -b "${cookiejar}" \ + --compressed \ + -H "X-Requested-With: XMLHttpRequest") + + _debug list_txt_response "${list_txt_response}" + + _check_2fa_miss "${list_txt_response}" + + # Find and delete all acme challenge entries for the $fulldomain. + _dns_entries=$(echo "$list_txt_response" | jq -r --arg fulldomain_idn "${fulldomain_idn}." ' + .rows[] | + label $out| + if .[0] != $fulldomain_idn then + break $out + else + .[4]| + capture("data-hash=\"(?[^\"]*)\" data-identifier=\"(?[^\"]*)\"";"g")| + .hash + " " + .identifier + end') + _dns_entries_cnt=$(echo "${_dns_entries}" | wc -l | grep -o '\d') + + _info " (entries found: ${_dns_entries_cnt})" + + _dns_entry_num=0 + + echo "${_dns_entries}" | while read -r _hash _identifier + do + ((_dns_entry_num++)) + + delete_txt_response=$(curl \ + "https://my.cyon.ch/domain/dnseditor/delete-record-async" \ + -s \ + --compressed \ + -b "${cookiejar}" \ + -H "X-Requested-With: XMLHttpRequest" \ + --data-urlencode "hash=${_hash}" \ + --data-urlencode "identifier=${_identifier}") + + _debug delete_txt_response "${delete_txt_response}" + + _check_2fa_miss "${delete_txt_response}" + + delete_txt_message=$(echo "${delete_txt_response}" | jq -r '.message') + delete_txt_status=$(echo "${delete_txt_response}" | jq -r '.status') + + # Skip if deleting TXT entry fails. + if [ "${delete_txt_status}" != "true" ]; then + if [ "${delete_txt_status}" = "null" ]; then + delete_txt_message=$(echo "${delete_txt_response}" | jq -r '.error.message') + fi + _err " [${_dns_entry_num}/${_dns_entries_cnt}] ${delete_txt_message} (${_identifier})" + else + _info " [${_dns_entry_num}/${_dns_entries_cnt}] success (${_identifier})" + fi + done + + _info " done" + _info "" +} + +_check_2fa_miss() { + # Did we miss the 2FA? + if [[ "$1" =~ "multi_factor_form" ]] ; then + _fail " Missed OTP authentication!" + fi +} + +_fail() { + _err "$1" + _err "" + _cleanup + exit 1 +} + +_cleanup() { + _info " - Cleanup." + _debug "Remove cookie jar: ${cookiejar}" + rm "${cookiejar}" 2>/dev/null + _info "" +} From c90fa3bcfc71f298cdbb1f2207df981ffc126c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 22 Nov 2016 00:45:56 +0100 Subject: [PATCH 141/620] Fix problems found by travis. --- dnsapi/dns_cyon.sh | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 95e690bb..3ebd3099 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -69,13 +69,16 @@ dns_cyon_rm() { _load_credentials() { # Convert loaded password to/from base64 as needed. - if [ "${cyon_password_b64}" ] ; then + if [ "${cyon_password_b64}" ]; then cyon_password="$(echo "${cyon_password_b64}" | _dbase64)" - elif [ "${cyon_password}" ] ; then + elif [ "${cyon_password}" ]; then cyon_password_b64="$(echo "${cyon_password}" | _base64)" fi - if [ -z "${cyon_username}" ] || [ -z "${cyon_password}" ] ; then + if [ -z "${cyon_username}" ] || [ -z "${cyon_password}" ]; then + cyon_username="" + cyon_password="" + cyon_otp_secret="" _err "" _err "You haven't set your cyon.ch login credentials yet." _err "Please set the required cyon environment variables." @@ -87,7 +90,7 @@ _load_credentials() { _debug "Save credentials to account.conf" _saveaccountconf cyon_username "${cyon_username}" _saveaccountconf cyon_password_b64 "$cyon_password_b64" - if [ ! -z "${cyon_otp_secret}" ] ; then + if [ ! -z "${cyon_otp_secret}" ]; then _saveaccountconf cyon_otp_secret "$cyon_otp_secret" fi } @@ -105,7 +108,7 @@ _load_parameters() { # Special case for IDNs, as cyon needs a domain environment change, # which uses the "pretty" instead of the punycode version. - if _is_idn "$1" ; then + if _is_idn "$1"; then if ! _exists idn; then _fail "Please install idn to process IDN names." fi @@ -168,16 +171,13 @@ _login() { _info " success" - # NECESSARY!! Load the main page after login, before the OTP check. curl "https://my.cyon.ch/" -s --compressed -b "${cookiejar}" >/dev/null - # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. - # 2FA authentication with OTP? - if [ ! -z "${cyon_otp_secret}" ] ; then + if [ ! -z "${cyon_otp_secret}" ]; then _info " - Authorising with OTP code..." if ! _exists oathtool; then @@ -298,9 +298,8 @@ _delete_txt() { _dns_entry_num=0 - echo "${_dns_entries}" | while read -r _hash _identifier - do - ((_dns_entry_num++)) + echo "${_dns_entries}" | while read -r _hash _identifier; do + _dns_entry_num=$((_dns_entry_num + 1)) delete_txt_response=$(curl \ "https://my.cyon.ch/domain/dnseditor/delete-record-async" \ @@ -335,7 +334,7 @@ _delete_txt() { _check_2fa_miss() { # Did we miss the 2FA? - if [[ "$1" =~ "multi_factor_form" ]] ; then + if test "${1#*multi_factor_form}" != "$1"; then _fail " Missed OTP authentication!" fi } From 0085e6f83bbf78bffd8f34681be6e6d6865a19a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 22 Nov 2016 15:21:04 +0100 Subject: [PATCH 142/620] Don't use jq to fetch list of DNS entries to be deleted. --- dnsapi/dns_cyon.sh | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 3ebd3099..605585e6 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -275,31 +275,23 @@ _delete_txt() { -s \ -b "${cookiejar}" \ --compressed \ - -H "X-Requested-With: XMLHttpRequest") + -H "X-Requested-With: XMLHttpRequest" | \ + sed -e 's/data-hash/\\ndata-hash/g') _debug list_txt_response "${list_txt_response}" _check_2fa_miss "${list_txt_response}" # Find and delete all acme challenge entries for the $fulldomain. - _dns_entries=$(echo "$list_txt_response" | jq -r --arg fulldomain_idn "${fulldomain_idn}." ' - .rows[] | - label $out| - if .[0] != $fulldomain_idn then - break $out - else - .[4]| - capture("data-hash=\"(?[^\"]*)\" data-identifier=\"(?[^\"]*)\"";"g")| - .hash + " " + .identifier - end') - _dns_entries_cnt=$(echo "${_dns_entries}" | wc -l | grep -o '\d') - - _info " (entries found: ${_dns_entries_cnt})" - - _dns_entry_num=0 + _dns_entries=$(echo -e "$list_txt_response" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p') echo "${_dns_entries}" | while read -r _hash _identifier; do - _dns_entry_num=$((_dns_entry_num + 1)) + dns_type="$(echo "$_identifier" | cut -d'|' -f1)" + dns_domain="$(echo "$_identifier" | cut -d'|' -f2)" + + if [ "${dns_type}" != "TXT" ] || [ "${dns_domain}" != "${fulldomain_idn}." ]; then + continue + fi delete_txt_response=$(curl \ "https://my.cyon.ch/domain/dnseditor/delete-record-async" \ @@ -322,9 +314,9 @@ _delete_txt() { if [ "${delete_txt_status}" = "null" ]; then delete_txt_message=$(echo "${delete_txt_response}" | jq -r '.error.message') fi - _err " [${_dns_entry_num}/${_dns_entries_cnt}] ${delete_txt_message} (${_identifier})" + _err " ${delete_txt_message} (${_identifier})" else - _info " [${_dns_entry_num}/${_dns_entries_cnt}] success (${_identifier})" + _info " success (${_identifier})" fi done From e7ee3a7dd55dc505b0cfb959b15161fb35704272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 22 Nov 2016 18:06:16 +0100 Subject: [PATCH 143/620] Remove jq completely to not require it as a dependency. --- dnsapi/dns_cyon.sh | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 605585e6..af5a225b 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -7,7 +7,6 @@ # # Dependencies: # ------------- -# - jq (get it here: https://stedolan.github.io/jq/download) # - oathtool (When using 2 Factor Authentication) # # Author: Armando Lüscher @@ -34,10 +33,6 @@ ######## dns_cyon_add() { - if ! _exists jq; then - _fail "Please install jq to use cyon.ch DNS API." - fi - _load_credentials _load_parameters "$@" @@ -165,8 +160,8 @@ _login() { _debug login_response "${login_response}" # Bail if login fails. - if [ "$(echo "${login_response}" | jq -r '.onSuccess')" != "success" ]; then - _fail " $(echo "${login_response}" | jq -r '.message')" + if [ "$(echo "${login_response}" | _get_response_success)" != "success" ]; then + _fail " $(echo "${login_response}" | _get_response_message)" fi _info " success" @@ -199,8 +194,8 @@ _login() { _debug otp_response "${otp_response}" # Bail if OTP authentication fails. - if [ "$(echo "${otp_response}" | jq -r '.onSuccess')" != "success" ]; then - _fail " $(echo "${otp_response}" | jq -r '.message')" + if [ "$(echo "${otp_response}" | _get_response_success)" != "success" ]; then + _fail " $(echo "${otp_response}" | _get_response_message)" fi _info " success" @@ -227,11 +222,11 @@ _domain_env() { _check_2fa_miss "${domain_env_response}" - domain_env_success=$(echo "${domain_env_response}" | jq -r '.authenticated') + domain_env_success=$(echo "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2) # Bail if domain environment change fails. if [ "${domain_env_success}" != "true" ]; then - _fail " $(echo "${domain_env_response}" | jq -r '.message')" + _fail " $(echo "${domain_env_response}" | _get_response_message)" fi _info " success" @@ -252,14 +247,11 @@ _add_txt() { _check_2fa_miss "${addtxt_response}" - addtxt_message=$(echo "${addtxt_response}" | jq -r '.message') - addtxt_status=$(echo "${addtxt_response}" | jq -r '.status') + addtxt_message=$(echo "${addtxt_response}" | _get_response_message) + addtxt_status=$(echo "${addtxt_response}" | _get_response_status) # Bail if adding TXT entry fails. if [ "${addtxt_status}" != "true" ]; then - if [ "${addtxt_status}" = "null" ]; then - addtxt_message=$(echo "${addtxt_response}" | jq -r '.error.message') - fi _fail " ${addtxt_message}" fi @@ -306,14 +298,11 @@ _delete_txt() { _check_2fa_miss "${delete_txt_response}" - delete_txt_message=$(echo "${delete_txt_response}" | jq -r '.message') - delete_txt_status=$(echo "${delete_txt_response}" | jq -r '.status') + delete_txt_message=$(echo "${delete_txt_response}" | _get_response_message) + delete_txt_status=$(echo "${delete_txt_response}" | _get_response_status) # Skip if deleting TXT entry fails. if [ "${delete_txt_status}" != "true" ]; then - if [ "${delete_txt_status}" = "null" ]; then - delete_txt_message=$(echo "${delete_txt_response}" | jq -r '.error.message') - fi _err " ${delete_txt_message} (${_identifier})" else _info " success (${_identifier})" @@ -324,6 +313,18 @@ _delete_txt() { _info "" } +_get_response_message() { + _egrep_o '"message":"[^"]*"' | cut -d : -f 2 | tr -d '"' +} + +_get_response_status() { + _egrep_o '"status":\w*' | cut -d : -f 2 +} + +_get_response_success() { + _egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"' +} + _check_2fa_miss() { # Did we miss the 2FA? if test "${1#*multi_factor_form}" != "$1"; then From 46b2ee3bae604619e3d191085581846853e25ad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 22 Nov 2016 18:31:38 +0100 Subject: [PATCH 144/620] Replace all echos with printf. --- dnsapi/dns_cyon.sh | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index af5a225b..28cb9e6e 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -65,9 +65,9 @@ dns_cyon_rm() { _load_credentials() { # Convert loaded password to/from base64 as needed. if [ "${cyon_password_b64}" ]; then - cyon_password="$(echo "${cyon_password_b64}" | _dbase64)" + cyon_password="$(printf "%s" "${cyon_password_b64}" | _dbase64)" elif [ "${cyon_password}" ]; then - cyon_password_b64="$(echo "${cyon_password}" | _base64)" + cyon_password_b64="$(printf "%s" "${cyon_password}" | _base64)" fi if [ -z "${cyon_username}" ] || [ -z "${cyon_password}" ]; then @@ -98,7 +98,7 @@ _is_idn() { _load_parameters() { # Read the required parameters to add the TXT entry. - fulldomain="$(echo "$1" | tr '[:upper:]' '[:lower:]')" + fulldomain="$(printf "%s" "$1" | tr '[:upper:]' '[:lower:]')" fulldomain_idn="${fulldomain}" # Special case for IDNs, as cyon needs a domain environment change, @@ -160,8 +160,8 @@ _login() { _debug login_response "${login_response}" # Bail if login fails. - if [ "$(echo "${login_response}" | _get_response_success)" != "success" ]; then - _fail " $(echo "${login_response}" | _get_response_message)" + if [ "$(printf "%s" "${login_response}" | _get_response_success)" != "success" ]; then + _fail " $(printf "%s" "${login_response}" | _get_response_message)" fi _info " success" @@ -194,8 +194,8 @@ _login() { _debug otp_response "${otp_response}" # Bail if OTP authentication fails. - if [ "$(echo "${otp_response}" | _get_response_success)" != "success" ]; then - _fail " $(echo "${otp_response}" | _get_response_message)" + if [ "$(printf "%s" "${otp_response}" | _get_response_success)" != "success" ]; then + _fail " $(printf "%s" "${otp_response}" | _get_response_message)" fi _info " success" @@ -208,7 +208,7 @@ _domain_env() { _info " - Changing domain environment..." # Get the "example.com" part of the full domain name. - domain_env=$(echo "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/') + domain_env=$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/') _debug "Changing domain environment to ${domain_env}" domain_env_response=$(curl \ @@ -222,11 +222,11 @@ _domain_env() { _check_2fa_miss "${domain_env_response}" - domain_env_success=$(echo "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2) + domain_env_success=$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2) # Bail if domain environment change fails. if [ "${domain_env_success}" != "true" ]; then - _fail " $(echo "${domain_env_response}" | _get_response_message)" + _fail " $(printf "%s" "${domain_env_response}" | _get_response_message)" fi _info " success" @@ -247,8 +247,8 @@ _add_txt() { _check_2fa_miss "${addtxt_response}" - addtxt_message=$(echo "${addtxt_response}" | _get_response_message) - addtxt_status=$(echo "${addtxt_response}" | _get_response_status) + addtxt_message=$(printf "%s" "${addtxt_response}" | _get_response_message) + addtxt_status=$(printf "%s" "${addtxt_response}" | _get_response_status) # Bail if adding TXT entry fails. if [ "${addtxt_status}" != "true" ]; then @@ -267,19 +267,19 @@ _delete_txt() { -s \ -b "${cookiejar}" \ --compressed \ - -H "X-Requested-With: XMLHttpRequest" | \ - sed -e 's/data-hash/\\ndata-hash/g') + -H "X-Requested-With: XMLHttpRequest" \ + | sed -e 's/data-hash/\\ndata-hash/g') _debug list_txt_response "${list_txt_response}" _check_2fa_miss "${list_txt_response}" # Find and delete all acme challenge entries for the $fulldomain. - _dns_entries=$(echo -e "$list_txt_response" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p') + _dns_entries=$(printf "%s" "$list_txt_response" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p') - echo "${_dns_entries}" | while read -r _hash _identifier; do - dns_type="$(echo "$_identifier" | cut -d'|' -f1)" - dns_domain="$(echo "$_identifier" | cut -d'|' -f2)" + printf "%s" "${_dns_entries}" | while read -r _hash _identifier; do + dns_type="$(printf "%s" "$_identifier" | cut -d'|' -f1)" + dns_domain="$(printf "%s" "$_identifier" | cut -d'|' -f2)" if [ "${dns_type}" != "TXT" ] || [ "${dns_domain}" != "${fulldomain_idn}." ]; then continue @@ -298,8 +298,8 @@ _delete_txt() { _check_2fa_miss "${delete_txt_response}" - delete_txt_message=$(echo "${delete_txt_response}" | _get_response_message) - delete_txt_status=$(echo "${delete_txt_response}" | _get_response_status) + delete_txt_message=$(printf "%s" "${delete_txt_response}" | _get_response_message) + delete_txt_status=$(printf "%s" "${delete_txt_response}" | _get_response_status) # Skip if deleting TXT entry fails. if [ "${delete_txt_status}" != "true" ]; then From 2698ef6c5f7795703c49c49e8225d6e99e94dc6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Wed, 23 Nov 2016 11:16:51 +0100 Subject: [PATCH 145/620] Return instead of exit. Clear OTP secret if environment variable is set to empty. This is for when the 2FA is disabled. Rename `_is_idn` function to `_is_idn_cyon`. Remove usage of curl (except for URL encoding of data). Instead of cleaning up the cookie jar, get rid of it completely and logout of cyon instead. --- dnsapi/dns_cyon.sh | 242 ++++++++++++++++++++++----------------------- 1 file changed, 118 insertions(+), 124 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 28cb9e6e..05079351 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -33,29 +33,23 @@ ######## dns_cyon_add() { - _load_credentials - _load_parameters "$@" - - _info_header "add" - _login - _domain_env - _add_txt - _cleanup - - return 0 + _load_credentials \ + && _load_parameters "$@" \ + && _info_header "add" \ + && _login \ + && _domain_env \ + && _add_txt \ + && _logout } dns_cyon_rm() { - _load_credentials - _load_parameters "$@" - - _info_header "delete" - _login - _domain_env - _delete_txt - _cleanup - - return 0 + _load_credentials \ + && _load_parameters "$@" \ + && _info_header "delete" \ + && _login \ + && _domain_env \ + && _delete_txt \ + && _logout } ######################### @@ -65,20 +59,22 @@ dns_cyon_rm() { _load_credentials() { # Convert loaded password to/from base64 as needed. if [ "${cyon_password_b64}" ]; then - cyon_password="$(printf "%s" "${cyon_password_b64}" | _dbase64)" + cyon_password="$(printf "%s" "${cyon_password_b64}" | _dbase64 "multiline")" elif [ "${cyon_password}" ]; then cyon_password_b64="$(printf "%s" "${cyon_password}" | _base64)" fi if [ -z "${cyon_username}" ] || [ -z "${cyon_password}" ]; then + # Dummy entries to satify script checker. cyon_username="" cyon_password="" cyon_otp_secret="" + _err "" _err "You haven't set your cyon.ch login credentials yet." _err "Please set the required cyon environment variables." _err "" - exit 1 + return 1 fi # Save the login credentials to the account.conf file. @@ -87,44 +83,52 @@ _load_credentials() { _saveaccountconf cyon_password_b64 "$cyon_password_b64" if [ ! -z "${cyon_otp_secret}" ]; then _saveaccountconf cyon_otp_secret "$cyon_otp_secret" + else + _clearaccountconf cyon_otp_secret fi } -_is_idn() { - _idn_temp=$(printf "%s" "$1" | tr -d "[0-9a-zA-Z.,-]") - _idn_temp2="$(printf "%s" "$1" | grep -o "xn--")" +_is_idn_cyon() { + _idn_temp="$(printf "%s" "${1}" | tr -d "[0-9a-zA-Z.,-_]")" + _idn_temp2="$(printf "%s" "${1}" | grep -o "xn--")" [ "$_idn_temp" ] || [ "$_idn_temp2" ] } +# comment on https://stackoverflow.com/a/10797966 +_urlencode_cyon() { + curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | cut -c 3- +} + _load_parameters() { # Read the required parameters to add the TXT entry. - fulldomain="$(printf "%s" "$1" | tr '[:upper:]' '[:lower:]')" + fulldomain="$(printf "%s" "${1}" | tr '[:upper:]' '[:lower:]')" fulldomain_idn="${fulldomain}" # Special case for IDNs, as cyon needs a domain environment change, # which uses the "pretty" instead of the punycode version. - if _is_idn "$1"; then + if _is_idn_cyon "${fulldomain}"; then if ! _exists idn; then - _fail "Please install idn to process IDN names." + _err "Please install idn to process IDN names." + _err "" + return 1 fi fulldomain="$(idn -u "${fulldomain}")" fulldomain_idn="$(idn -a "${fulldomain}")" fi - _debug fulldomain "$fulldomain" - _debug fulldomain_idn "$fulldomain_idn" + _debug fulldomain "${fulldomain}" + _debug fulldomain_idn "${fulldomain_idn}" - txtvalue="$2" - _debug txtvalue "$txtvalue" + txtvalue="${2}" + _debug txtvalue "${txtvalue}" - # Cookiejar required for login session, as cyon.ch has no official API (yet). - cookiejar=$(tempfile) - _debug cookiejar "$cookiejar" + # This header is required for curl calls. + _H1="X-Requested-With: XMLHttpRequest" } _info_header() { - if [ "$1" = "add" ]; then + if [ "${1}" = "add" ]; then _info "" _info "+---------------------------------------------+" _info "| Adding DNS TXT entry to your cyon.ch domain |" @@ -132,42 +136,46 @@ _info_header() { _info "" _info " * Full Domain: ${fulldomain}" _info " * TXT Value: ${txtvalue}" - _info " * Cookie Jar: ${cookiejar}" _info "" - elif [ "$1" = "delete" ]; then + elif [ "${1}" = "delete" ]; then _info "" _info "+-------------------------------------------------+" _info "| Deleting DNS TXT entry from your cyon.ch domain |" _info "+-------------------------------------------------+" _info "" _info " * Full Domain: ${fulldomain}" - _info " * Cookie Jar: ${cookiejar}" _info "" fi } +_get_cookie_header() { + printf "%s" "$(sed -n 's/Set-\(Cookie:.*cyon=[^;]*\).*/\1/p' "$HTTP_HEADER" | _tail_n 1)" +} + _login() { _info " - Logging in..." - login_response=$(curl \ - "https://my.cyon.ch/auth/index/dologin-async" \ - -s \ - -c "${cookiejar}" \ - -H "X-Requested-With: XMLHttpRequest" \ - --data-urlencode "username=${cyon_username}" \ - --data-urlencode "password=${cyon_password}" \ - --data-urlencode "pathname=/") + username_encoded="$(printf "%s" "${cyon_username}" | _urlencode_cyon)" + password_encoded="$(printf "%s" "${cyon_password}" | _urlencode_cyon)" + + login_url="https://my.cyon.ch/auth/index/dologin-async" + login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")" + + login_response="$(_post "$login_data" "$login_url")" _debug login_response "${login_response}" # Bail if login fails. if [ "$(printf "%s" "${login_response}" | _get_response_success)" != "success" ]; then - _fail " $(printf "%s" "${login_response}" | _get_response_message)" + _err " $(printf "%s" "${login_response}" | _get_response_message)" + _err "" + return 1 fi _info " success" - # NECESSARY!! Load the main page after login, before the OTP check. - curl "https://my.cyon.ch/" -s --compressed -b "${cookiejar}" >/dev/null + # NECESSARY!! Load the main page after login, to get the new cookie. + _H2="$(_get_cookie_header)" + _get "https://my.cyon.ch/" > /dev/null # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. @@ -176,26 +184,25 @@ _login() { _info " - Authorising with OTP code..." if ! _exists oathtool; then - _fail "Please install oathtool to use 2 Factor Authentication." + _err "Please install oathtool to use 2 Factor Authentication." + _err "" + return 1 fi # Get OTP code with the defined secret. - otp_code=$(oathtool --base32 --totp "${cyon_otp_secret}" 2>/dev/null) + otp_code="$(oathtool --base32 --totp "${cyon_otp_secret}" 2>/dev/null)" - otp_response=$(curl \ - "https://my.cyon.ch/auth/multi-factor/domultifactorauth-async" \ - -s \ - --compressed \ - -b "${cookiejar}" \ - -c "${cookiejar}" \ - -H "X-Requested-With: XMLHttpRequest" \ - -d "totpcode=${otp_code}&pathname=%2F&rememberme=0") + login_otp_url="https://my.cyon.ch/auth/multi-factor/domultifactorauth-async" + login_otp_data="totpcode=${otp_code}&pathname=%2F&rememberme=0" - _debug otp_response "${otp_response}" + login_otp_response="$(_post "$login_otp_data" "$login_otp_url")" + _debug login_otp_response "${login_otp_response}" # Bail if OTP authentication fails. - if [ "$(printf "%s" "${otp_response}" | _get_response_success)" != "success" ]; then - _fail " $(printf "%s" "${otp_response}" | _get_response_message)" + if [ "$(printf "%s" "${login_otp_response}" | _get_response_success)" != "success" ]; then + _err " $(printf "%s" "${login_otp_response}" | _get_response_message)" + _err "" + return 1 fi _info " success" @@ -204,29 +211,36 @@ _login() { _info "" } +_logout() { + _info " - Logging out..." + + _get "https://my.cyon.ch/auth/index/dologout" > /dev/null + + _info " success" + _info "" +} + _domain_env() { _info " - Changing domain environment..." # Get the "example.com" part of the full domain name. - domain_env=$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/') + domain_env="$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/')" _debug "Changing domain environment to ${domain_env}" - domain_env_response=$(curl \ - "https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/domain%3A${domain_env}" \ - -s \ - --compressed \ - -b "${cookiejar}" \ - -H "X-Requested-With: XMLHttpRequest") + domain_env_url="https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/domain%3A${domain_env}" + domain_env_response="$(_get "${domain_env_url}")" _debug domain_env_response "${domain_env_response}" - _check_2fa_miss "${domain_env_response}" + if ! _check_if_2fa_missed "${domain_env_response}"; then return 1; fi - domain_env_success=$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2) + domain_env_success="$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2)" # Bail if domain environment change fails. if [ "${domain_env_success}" != "true" ]; then - _fail " $(printf "%s" "${domain_env_response}" | _get_response_message)" + _err " $(printf "%s" "${domain_env_response}" | _get_response_message)" + _err "" + return 1 fi _info " success" @@ -235,47 +249,41 @@ _domain_env() { _add_txt() { _info " - Adding DNS TXT entry..." - addtxt_response=$(curl \ - "https://my.cyon.ch/domain/dnseditor/add-record-async" \ - -s \ - --compressed \ - -b "${cookiejar}" \ - -H "X-Requested-With: XMLHttpRequest" \ - -d "zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}") - _debug addtxt_response "${addtxt_response}" + add_txt_url="https://my.cyon.ch/domain/dnseditor/add-record-async" + add_txt_data="zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}" - _check_2fa_miss "${addtxt_response}" + add_txt_response="$(_post "$add_txt_data" "$add_txt_url")" + _debug add_txt_response "${add_txt_response}" - addtxt_message=$(printf "%s" "${addtxt_response}" | _get_response_message) - addtxt_status=$(printf "%s" "${addtxt_response}" | _get_response_status) + if ! _check_if_2fa_missed "${add_txt_response}"; then return 1; fi + + add_txt_message="$(printf "%s" "${add_txt_response}" | _get_response_message)" + add_txt_status="$(printf "%s" "${add_txt_response}" | _get_response_status)" # Bail if adding TXT entry fails. - if [ "${addtxt_status}" != "true" ]; then - _fail " ${addtxt_message}" + if [ "${add_txt_status}" != "true" ]; then + _err " ${add_txt_message}" + _err "" + return 1 fi - _info " success" + _info " success (TXT|${fulldomain_idn}.|${txtvalue})" _info "" } _delete_txt() { _info " - Deleting DNS TXT entry..." - list_txt_response=$(curl \ - "https://my.cyon.ch/domain/dnseditor/list-async" \ - -s \ - -b "${cookiejar}" \ - --compressed \ - -H "X-Requested-With: XMLHttpRequest" \ - | sed -e 's/data-hash/\\ndata-hash/g') + list_txt_url="https://my.cyon.ch/domain/dnseditor/list-async" + list_txt_response="$(_get "${list_txt_url}" | sed -e 's/data-hash/\\ndata-hash/g')" _debug list_txt_response "${list_txt_response}" - _check_2fa_miss "${list_txt_response}" + if ! _check_if_2fa_missed "${list_txt_response}"; then return 1; fi # Find and delete all acme challenge entries for the $fulldomain. - _dns_entries=$(printf "%s" "$list_txt_response" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p') + _dns_entries="$(printf "%b\n" "${list_txt_response}" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p')" printf "%s" "${_dns_entries}" | while read -r _hash _identifier; do dns_type="$(printf "%s" "$_identifier" | cut -d'|' -f1)" @@ -285,21 +293,19 @@ _delete_txt() { continue fi - delete_txt_response=$(curl \ - "https://my.cyon.ch/domain/dnseditor/delete-record-async" \ - -s \ - --compressed \ - -b "${cookiejar}" \ - -H "X-Requested-With: XMLHttpRequest" \ - --data-urlencode "hash=${_hash}" \ - --data-urlencode "identifier=${_identifier}") + hash_encoded="$(printf "%s" "${_hash}" | _urlencode_cyon)" + identifier_encoded="$(printf "%s" "${_identifier}" | _urlencode_cyon)" + + delete_txt_url="https://my.cyon.ch/domain/dnseditor/delete-record-async" + delete_txt_data="$(printf "%s" "hash=${hash_encoded}&identifier=${identifier_encoded}")" + delete_txt_response="$(_post "$delete_txt_data" "$delete_txt_url")" _debug delete_txt_response "${delete_txt_response}" - _check_2fa_miss "${delete_txt_response}" + if ! _check_if_2fa_missed "${delete_txt_response}"; then return 1; fi - delete_txt_message=$(printf "%s" "${delete_txt_response}" | _get_response_message) - delete_txt_status=$(printf "%s" "${delete_txt_response}" | _get_response_status) + delete_txt_message="$(printf "%s" "${delete_txt_response}" | _get_response_message)" + delete_txt_status="$(printf "%s" "${delete_txt_response}" | _get_response_status)" # Skip if deleting TXT entry fails. if [ "${delete_txt_status}" != "true" ]; then @@ -325,23 +331,11 @@ _get_response_success() { _egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"' } -_check_2fa_miss() { +_check_if_2fa_missed() { # Did we miss the 2FA? - if test "${1#*multi_factor_form}" != "$1"; then - _fail " Missed OTP authentication!" - fi -} - -_fail() { - _err "$1" + if test "${1#*multi_factor_form}" != "${1}"; then + _err " Missed OTP authentication!" _err "" - _cleanup - exit 1 -} - -_cleanup() { - _info " - Cleanup." - _debug "Remove cookie jar: ${cookiejar}" - rm "${cookiejar}" 2>/dev/null - _info "" + return 1 + fi } From 98b3dcbf37fd462609b92e72080542e4b01b48c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Fri, 16 Dec 2016 03:44:48 +0100 Subject: [PATCH 146/620] Prefix all private functions with `_cyon`. Satisfy shellcheck. --- dnsapi/dns_cyon.sh | 106 ++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 05079351..3a441aaf 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -33,30 +33,30 @@ ######## dns_cyon_add() { - _load_credentials \ - && _load_parameters "$@" \ - && _info_header "add" \ - && _login \ - && _domain_env \ - && _add_txt \ - && _logout + _cyon_load_credentials \ + && _cyon_load_parameters "$@" \ + && _cyon_print_header "add" \ + && _cyon_login \ + && _cyon_change_domain_env \ + && _cyon_add_txt \ + && _cyon_logout } dns_cyon_rm() { - _load_credentials \ - && _load_parameters "$@" \ - && _info_header "delete" \ - && _login \ - && _domain_env \ - && _delete_txt \ - && _logout + _cyon_load_credentials \ + && _cyon_load_parameters "$@" \ + && _cyon_print_header "delete" \ + && _cyon_login \ + && _cyon_change_domain_env \ + && _cyon_delete_txt \ + && _cyon_logout } ######################### ### PRIVATE FUNCTIONS ### ######################### -_load_credentials() { +_cyon_load_credentials() { # Convert loaded password to/from base64 as needed. if [ "${cyon_password_b64}" ]; then cyon_password="$(printf "%s" "${cyon_password_b64}" | _dbase64 "multiline")" @@ -88,25 +88,25 @@ _load_credentials() { fi } -_is_idn_cyon() { +_cyon_is_idn() { _idn_temp="$(printf "%s" "${1}" | tr -d "[0-9a-zA-Z.,-_]")" _idn_temp2="$(printf "%s" "${1}" | grep -o "xn--")" [ "$_idn_temp" ] || [ "$_idn_temp2" ] } # comment on https://stackoverflow.com/a/10797966 -_urlencode_cyon() { - curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | cut -c 3- +_cyon_urlencode() { + curl -Gso /dev/null -w "%{url_effective}" --data-urlencode @- "" | cut -c 3- } -_load_parameters() { +_cyon_load_parameters() { # Read the required parameters to add the TXT entry. fulldomain="$(printf "%s" "${1}" | tr '[:upper:]' '[:lower:]')" fulldomain_idn="${fulldomain}" # Special case for IDNs, as cyon needs a domain environment change, # which uses the "pretty" instead of the punycode version. - if _is_idn_cyon "${fulldomain}"; then + if _cyon_is_idn "${fulldomain}"; then if ! _exists idn; then _err "Please install idn to process IDN names." _err "" @@ -127,7 +127,7 @@ _load_parameters() { _H1="X-Requested-With: XMLHttpRequest" } -_info_header() { +_cyon_print_header() { if [ "${1}" = "add" ]; then _info "" _info "+---------------------------------------------+" @@ -148,15 +148,15 @@ _info_header() { fi } -_get_cookie_header() { +_cyon_get_cookie_header() { printf "%s" "$(sed -n 's/Set-\(Cookie:.*cyon=[^;]*\).*/\1/p' "$HTTP_HEADER" | _tail_n 1)" } -_login() { +_cyon_login() { _info " - Logging in..." - username_encoded="$(printf "%s" "${cyon_username}" | _urlencode_cyon)" - password_encoded="$(printf "%s" "${cyon_password}" | _urlencode_cyon)" + username_encoded="$(printf "%s" "${cyon_username}" | _cyon_urlencode)" + password_encoded="$(printf "%s" "${cyon_password}" | _cyon_urlencode)" login_url="https://my.cyon.ch/auth/index/dologin-async" login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")" @@ -165,8 +165,8 @@ _login() { _debug login_response "${login_response}" # Bail if login fails. - if [ "$(printf "%s" "${login_response}" | _get_response_success)" != "success" ]; then - _err " $(printf "%s" "${login_response}" | _get_response_message)" + if [ "$(printf "%s" "${login_response}" | _cyon_get_response_success)" != "success" ]; then + _err " $(printf "%s" "${login_response}" | _cyon_get_response_message)" _err "" return 1 fi @@ -174,8 +174,8 @@ _login() { _info " success" # NECESSARY!! Load the main page after login, to get the new cookie. - _H2="$(_get_cookie_header)" - _get "https://my.cyon.ch/" > /dev/null + _H2="$(_cyon_get_cookie_header)" + _get "https://my.cyon.ch/" >/dev/null # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. @@ -199,8 +199,8 @@ _login() { _debug login_otp_response "${login_otp_response}" # Bail if OTP authentication fails. - if [ "$(printf "%s" "${login_otp_response}" | _get_response_success)" != "success" ]; then - _err " $(printf "%s" "${login_otp_response}" | _get_response_message)" + if [ "$(printf "%s" "${login_otp_response}" | _cyon_get_response_success)" != "success" ]; then + _err " $(printf "%s" "${login_otp_response}" | _cyon_get_response_message)" _err "" return 1 fi @@ -211,16 +211,16 @@ _login() { _info "" } -_logout() { +_cyon_logout() { _info " - Logging out..." - _get "https://my.cyon.ch/auth/index/dologout" > /dev/null + _get "https://my.cyon.ch/auth/index/dologout" >/dev/null _info " success" _info "" } -_domain_env() { +_cyon_change_domain_env() { _info " - Changing domain environment..." # Get the "example.com" part of the full domain name. @@ -232,13 +232,13 @@ _domain_env() { domain_env_response="$(_get "${domain_env_url}")" _debug domain_env_response "${domain_env_response}" - if ! _check_if_2fa_missed "${domain_env_response}"; then return 1; fi + if ! _cyon_check_if_2fa_missed "${domain_env_response}"; then return 1; fi domain_env_success="$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2)" # Bail if domain environment change fails. if [ "${domain_env_success}" != "true" ]; then - _err " $(printf "%s" "${domain_env_response}" | _get_response_message)" + _err " $(printf "%s" "${domain_env_response}" | _cyon_get_response_message)" _err "" return 1 fi @@ -247,7 +247,7 @@ _domain_env() { _info "" } -_add_txt() { +_cyon_add_txt() { _info " - Adding DNS TXT entry..." add_txt_url="https://my.cyon.ch/domain/dnseditor/add-record-async" @@ -256,10 +256,10 @@ _add_txt() { add_txt_response="$(_post "$add_txt_data" "$add_txt_url")" _debug add_txt_response "${add_txt_response}" - if ! _check_if_2fa_missed "${add_txt_response}"; then return 1; fi + if ! _cyon_check_if_2fa_missed "${add_txt_response}"; then return 1; fi - add_txt_message="$(printf "%s" "${add_txt_response}" | _get_response_message)" - add_txt_status="$(printf "%s" "${add_txt_response}" | _get_response_status)" + add_txt_message="$(printf "%s" "${add_txt_response}" | _cyon_get_response_message)" + add_txt_status="$(printf "%s" "${add_txt_response}" | _cyon_get_response_status)" # Bail if adding TXT entry fails. if [ "${add_txt_status}" != "true" ]; then @@ -272,7 +272,7 @@ _add_txt() { _info "" } -_delete_txt() { +_cyon_delete_txt() { _info " - Deleting DNS TXT entry..." list_txt_url="https://my.cyon.ch/domain/dnseditor/list-async" @@ -280,7 +280,7 @@ _delete_txt() { list_txt_response="$(_get "${list_txt_url}" | sed -e 's/data-hash/\\ndata-hash/g')" _debug list_txt_response "${list_txt_response}" - if ! _check_if_2fa_missed "${list_txt_response}"; then return 1; fi + if ! _cyon_check_if_2fa_missed "${list_txt_response}"; then return 1; fi # Find and delete all acme challenge entries for the $fulldomain. _dns_entries="$(printf "%b\n" "${list_txt_response}" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p')" @@ -293,8 +293,8 @@ _delete_txt() { continue fi - hash_encoded="$(printf "%s" "${_hash}" | _urlencode_cyon)" - identifier_encoded="$(printf "%s" "${_identifier}" | _urlencode_cyon)" + hash_encoded="$(printf "%s" "${_hash}" | _cyon_urlencode)" + identifier_encoded="$(printf "%s" "${_identifier}" | _cyon_urlencode)" delete_txt_url="https://my.cyon.ch/domain/dnseditor/delete-record-async" delete_txt_data="$(printf "%s" "hash=${hash_encoded}&identifier=${identifier_encoded}")" @@ -302,10 +302,10 @@ _delete_txt() { delete_txt_response="$(_post "$delete_txt_data" "$delete_txt_url")" _debug delete_txt_response "${delete_txt_response}" - if ! _check_if_2fa_missed "${delete_txt_response}"; then return 1; fi + if ! _cyon_check_if_2fa_missed "${delete_txt_response}"; then return 1; fi - delete_txt_message="$(printf "%s" "${delete_txt_response}" | _get_response_message)" - delete_txt_status="$(printf "%s" "${delete_txt_response}" | _get_response_status)" + delete_txt_message="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_message)" + delete_txt_status="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_status)" # Skip if deleting TXT entry fails. if [ "${delete_txt_status}" != "true" ]; then @@ -319,23 +319,23 @@ _delete_txt() { _info "" } -_get_response_message() { +_cyon_get_response_message() { _egrep_o '"message":"[^"]*"' | cut -d : -f 2 | tr -d '"' } -_get_response_status() { +_cyon_get_response_status() { _egrep_o '"status":\w*' | cut -d : -f 2 } -_get_response_success() { +_cyon_get_response_success() { _egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"' } -_check_if_2fa_missed() { +_cyon_check_if_2fa_missed() { # Did we miss the 2FA? if test "${1#*multi_factor_form}" != "${1}"; then _err " Missed OTP authentication!" - _err "" - return 1 + _err "" + return 1 fi } From edfefb6763e6e2ecc523aac762e4db4d247bf72f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 27 Dec 2016 00:56:05 +0100 Subject: [PATCH 147/620] Add usage instructions and repo link to post issues. --- README.md | 1 + dnsapi/README.md | 18 ++++++++++++++++++ dnsapi/dns_cyon.sh | 25 +++++-------------------- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index f1c74806..5f82effb 100644 --- a/README.md +++ b/README.md @@ -272,6 +272,7 @@ You don't have to do anything manually! 1. Alwaysdata.com API 1. Linode.com API 1. FreeDNS (https://freedns.afraid.org/) +1. cyon.ch **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 6a86bf4c..70af17e7 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -305,6 +305,24 @@ Note that you cannot use acme.sh automatic DNS validation for FreeDNS public dom you create under a FreeDNS public domain. You must own the top level domain in order to automaitcally validate with acme.sh at FreeDNS. +## 16. Use cyon.ch + +You only need to set your cyon.ch login credentials. +If you also have 2 Factor Authentication (OTP) enabled, you need to set your secret token too and have `oathtool` installed. + +``` +export cyon_username="your_cyon_username" +export cyon_password="your_cyon_password" +export cyon_otp_secret="your_otp_secret" # Only required if using 2FA +``` + +To issue a cert: +``` +acme.sh --issue --dns dns_cyon -d example.com -d www.example.com +``` + +The `cyon_username`, `cyon_password` and `cyon_otp_secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 3a441aaf..6c9c5c5d 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -9,27 +9,12 @@ # ------------- # - oathtool (When using 2 Factor Authentication) # -# Author: Armando Lüscher -######## - -######## -# Define cyon.ch login credentials: -# -# Either set them here: (uncomment these lines) +# Issues: +# ------- +# Any issues / questions / suggestions can be posted here: +# https://github.com/noplanman/cyon-api/issues # -# cyon_username='your_cyon_username' -# cyon_password='your_cyon_password' -# cyon_otp_secret='your_otp_secret' # Only required if using 2FA -# -# ...or export them as environment variables in your shell: -# -# $ export cyon_username='your_cyon_username' -# $ export cyon_password='your_cyon_password' -# $ export cyon_otp_secret='your_otp_secret' # Only required if using 2FA -# -# *Note:* -# After the first run, the credentials are saved in the "account.conf" -# file, so any hard-coded or environment variables can then be removed. +# Author: Armando Lüscher ######## dns_cyon_add() { From 09eccf6fc075c8f39ff0ec9ee1d7d20aa9826b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Wed, 28 Dec 2016 13:37:24 +0100 Subject: [PATCH 148/620] Use more flexible version of uppercase to lowercase conversion. --- dnsapi/dns_cyon.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 6c9c5c5d..ab8a38e5 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -86,7 +86,7 @@ _cyon_urlencode() { _cyon_load_parameters() { # Read the required parameters to add the TXT entry. - fulldomain="$(printf "%s" "${1}" | tr '[:upper:]' '[:lower:]')" + fulldomain="$(printf "%s" "${1}" | tr '[A-Z]' '[a-z]')" fulldomain_idn="${fulldomain}" # Special case for IDNs, as cyon needs a domain environment change, From afa3fc8bf921209476329cf9ebc6f58415dc0907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Wed, 28 Dec 2016 14:51:39 +0100 Subject: [PATCH 149/620] Adapt to use general naming rule for account variables. --- dnsapi/README.md | 8 ++++---- dnsapi/dns_cyon.sh | 34 +++++++++++++++++----------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 70af17e7..fd88d579 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -311,9 +311,9 @@ You only need to set your cyon.ch login credentials. If you also have 2 Factor Authentication (OTP) enabled, you need to set your secret token too and have `oathtool` installed. ``` -export cyon_username="your_cyon_username" -export cyon_password="your_cyon_password" -export cyon_otp_secret="your_otp_secret" # Only required if using 2FA +export CY_Username="your_cyon_username" +export CY_Password="your_cyon_password" +export CY_OTP_Secret="your_otp_secret" # Only required if using 2FA ``` To issue a cert: @@ -321,7 +321,7 @@ To issue a cert: acme.sh --issue --dns dns_cyon -d example.com -d www.example.com ``` -The `cyon_username`, `cyon_password` and `cyon_otp_secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +The `CY_Username`, `CY_Password` and `CY_OTP_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. # Use custom API diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index ab8a38e5..ca952db4 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -43,17 +43,17 @@ dns_cyon_rm() { _cyon_load_credentials() { # Convert loaded password to/from base64 as needed. - if [ "${cyon_password_b64}" ]; then - cyon_password="$(printf "%s" "${cyon_password_b64}" | _dbase64 "multiline")" - elif [ "${cyon_password}" ]; then - cyon_password_b64="$(printf "%s" "${cyon_password}" | _base64)" + if [ "${CY_Password_B64}" ]; then + CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64 "multiline")" + elif [ "${CY_Password}" ]; then + CY_Password_B64="$(printf "%s" "${CY_Password}" | _base64)" fi - if [ -z "${cyon_username}" ] || [ -z "${cyon_password}" ]; then + if [ -z "${CY_Username}" ] || [ -z "${CY_Password}" ]; then # Dummy entries to satify script checker. - cyon_username="" - cyon_password="" - cyon_otp_secret="" + CY_Username="" + CY_Password="" + CY_OTP_Secret="" _err "" _err "You haven't set your cyon.ch login credentials yet." @@ -64,12 +64,12 @@ _cyon_load_credentials() { # Save the login credentials to the account.conf file. _debug "Save credentials to account.conf" - _saveaccountconf cyon_username "${cyon_username}" - _saveaccountconf cyon_password_b64 "$cyon_password_b64" - if [ ! -z "${cyon_otp_secret}" ]; then - _saveaccountconf cyon_otp_secret "$cyon_otp_secret" + _saveaccountconf CY_Username "${CY_Username}" + _saveaccountconf CY_Password_B64 "$CY_Password_B64" + if [ ! -z "${CY_OTP_Secret}" ]; then + _saveaccountconf CY_OTP_Secret "$CY_OTP_Secret" else - _clearaccountconf cyon_otp_secret + _clearaccountconf CY_OTP_Secret fi } @@ -140,8 +140,8 @@ _cyon_get_cookie_header() { _cyon_login() { _info " - Logging in..." - username_encoded="$(printf "%s" "${cyon_username}" | _cyon_urlencode)" - password_encoded="$(printf "%s" "${cyon_password}" | _cyon_urlencode)" + username_encoded="$(printf "%s" "${CY_Username}" | _cyon_urlencode)" + password_encoded="$(printf "%s" "${CY_Password}" | _cyon_urlencode)" login_url="https://my.cyon.ch/auth/index/dologin-async" login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")" @@ -165,7 +165,7 @@ _cyon_login() { # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. # 2FA authentication with OTP? - if [ ! -z "${cyon_otp_secret}" ]; then + if [ ! -z "${CY_OTP_Secret}" ]; then _info " - Authorising with OTP code..." if ! _exists oathtool; then @@ -175,7 +175,7 @@ _cyon_login() { fi # Get OTP code with the defined secret. - otp_code="$(oathtool --base32 --totp "${cyon_otp_secret}" 2>/dev/null)" + otp_code="$(oathtool --base32 --totp "${CY_OTP_Secret}" 2>/dev/null)" login_otp_url="https://my.cyon.ch/auth/multi-factor/domultifactorauth-async" login_otp_data="totpcode=${otp_code}&pathname=%2F&rememberme=0" From ce9fae82bd7a31c52514e5f0f7d6f6a0f5854117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Thu, 29 Dec 2016 16:12:42 +0100 Subject: [PATCH 150/620] Update cookie retrieval using _egrep_o (thanks @Neilpang) --- dnsapi/dns_cyon.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index ca952db4..0390592a 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -134,7 +134,7 @@ _cyon_print_header() { } _cyon_get_cookie_header() { - printf "%s" "$(sed -n 's/Set-\(Cookie:.*cyon=[^;]*\).*/\1/p' "$HTTP_HEADER" | _tail_n 1)" + printf "Cookie: %s" "$(cat "$HTTP_HEADER" | grep "cyon=" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'cyon=[^;]*;' | tr -d ';')" } _cyon_login() { From 6e8dcdce7834938db893f85955aef27e1d71ca9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Wed, 4 Jan 2017 03:19:58 +0100 Subject: [PATCH 151/620] Satisfy shellcheck. --- dnsapi/dns_cyon.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 0390592a..54162198 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -134,7 +134,7 @@ _cyon_print_header() { } _cyon_get_cookie_header() { - printf "Cookie: %s" "$(cat "$HTTP_HEADER" | grep "cyon=" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'cyon=[^;]*;' | tr -d ';')" + printf "Cookie: %s" "$(grep "cyon=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'cyon=[^;]*;' | tr -d ';')" } _cyon_login() { From 9499a1142bfdaf0c3fb9f729421fd8ae853705ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Mon, 30 Jan 2017 16:36:49 +0100 Subject: [PATCH 152/620] Remove custom URL encoding and use library's implementation. --- dnsapi/dns_cyon.sh | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 54162198..d225138b 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -79,11 +79,6 @@ _cyon_is_idn() { [ "$_idn_temp" ] || [ "$_idn_temp2" ] } -# comment on https://stackoverflow.com/a/10797966 -_cyon_urlencode() { - curl -Gso /dev/null -w "%{url_effective}" --data-urlencode @- "" | cut -c 3- -} - _cyon_load_parameters() { # Read the required parameters to add the TXT entry. fulldomain="$(printf "%s" "${1}" | tr '[A-Z]' '[a-z]')" @@ -140,8 +135,8 @@ _cyon_get_cookie_header() { _cyon_login() { _info " - Logging in..." - username_encoded="$(printf "%s" "${CY_Username}" | _cyon_urlencode)" - password_encoded="$(printf "%s" "${CY_Password}" | _cyon_urlencode)" + username_encoded="$(printf "%s" "${CY_Username}" | _url_encode)" + password_encoded="$(printf "%s" "${CY_Password}" | _url_encode)" login_url="https://my.cyon.ch/auth/index/dologin-async" login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")" @@ -278,8 +273,8 @@ _cyon_delete_txt() { continue fi - hash_encoded="$(printf "%s" "${_hash}" | _cyon_urlencode)" - identifier_encoded="$(printf "%s" "${_identifier}" | _cyon_urlencode)" + hash_encoded="$(printf "%s" "${_hash}" | _url_encode)" + identifier_encoded="$(printf "%s" "${_identifier}" | _url_encode)" delete_txt_url="https://my.cyon.ch/domain/dnseditor/delete-record-async" delete_txt_data="$(printf "%s" "hash=${hash_encoded}&identifier=${identifier_encoded}")" From 884f70fb399cd73c1004c9eb5c11a582e9e35c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Tue, 31 Jan 2017 15:23:40 +0100 Subject: [PATCH 153/620] Remove square brackets from ranges. Export curl header variables. --- dnsapi/dns_cyon.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index d225138b..85ff028c 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -74,14 +74,14 @@ _cyon_load_credentials() { } _cyon_is_idn() { - _idn_temp="$(printf "%s" "${1}" | tr -d "[0-9a-zA-Z.,-_]")" + _idn_temp="$(printf "%s" "${1}" | tr -d "0-9a-zA-Z.,-_")" _idn_temp2="$(printf "%s" "${1}" | grep -o "xn--")" [ "$_idn_temp" ] || [ "$_idn_temp2" ] } _cyon_load_parameters() { # Read the required parameters to add the TXT entry. - fulldomain="$(printf "%s" "${1}" | tr '[A-Z]' '[a-z]')" + fulldomain="$(printf "%s" "${1}" | tr "A-Z" "a-z")" fulldomain_idn="${fulldomain}" # Special case for IDNs, as cyon needs a domain environment change, @@ -105,6 +105,7 @@ _cyon_load_parameters() { # This header is required for curl calls. _H1="X-Requested-With: XMLHttpRequest" + export _H1 } _cyon_print_header() { @@ -155,6 +156,8 @@ _cyon_login() { # NECESSARY!! Load the main page after login, to get the new cookie. _H2="$(_cyon_get_cookie_header)" + export _H2 + _get "https://my.cyon.ch/" >/dev/null # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. From 3e1418d662a3dc15a8359c2441397d63688d596e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Sun, 12 Feb 2017 12:30:06 +0100 Subject: [PATCH 154/620] Use gloo item key for environment change, to support different account types. (this isn't working 100% yet, still looking for a solution) --- dnsapi/dns_cyon.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 85ff028c..0ced4217 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -210,7 +210,10 @@ _cyon_change_domain_env() { domain_env="$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/')" _debug "Changing domain environment to ${domain_env}" - domain_env_url="https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/domain%3A${domain_env}" + gloo_item_key="$(_get "https://my.cyon.ch/domain/" | tr '\n' ' ' | sed -E -e "s/.*data-domain=\"${domain_env}\"[^<]*data-itemkey=\"([^\"]*).*/\1/")" + _debug gloo_item_key "${gloo_item_key}" + + domain_env_url="https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/${gloo_item_key}" domain_env_response="$(_get "${domain_env_url}")" _debug domain_env_response "${domain_env_response}" From 9d725af60221519a8ac4cc976a0af49ff0be2e26 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 13 Feb 2017 23:29:37 +0800 Subject: [PATCH 155/620] support nginx mode --- README.md | 32 ++++++-- acme.sh | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 235 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index f1c74806..edc4555c 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ https://github.com/Neilpang/acmetest - Webroot mode - Standalone mode - Apache mode +- Nginx mode - DNS mode - [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode) @@ -215,8 +216,27 @@ acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert +# 7. Use Nginx mode -# 7. Use DNS mode: +**(requires you to be root/sudoer, since it is required to interact with Nginx server)** + +If you are running a web server, Apache or Nginx, it is recommended to use the `Webroot mode`. + +Particularly, if you are running an nginx server, you can use nginx mode instead. This mode doesn't write any files to your web root folder. + +Just set string "nginx" as the second argument. + +It will configure nginx server automatically to verify the domain and then restore the nginx config to the original version. + +So, the config is not changed. + +``` +acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com +``` + +More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert + +# 8. Use DNS mode: Support the `dns-01` challenge. @@ -247,7 +267,7 @@ acme.sh --renew -d example.com Ok, it's finished. -# 8. Automatic DNS API integration +# 9. Automatic DNS API integration If your DNS provider supports API access, we can use that API to automatically issue the certs. @@ -280,7 +300,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) -# 9. Issue ECC certificates +# 10. Issue ECC certificates `Let's Encrypt` can now issue **ECDSA** certificates. @@ -311,7 +331,7 @@ Valid values are: 3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)** -# 10. How to renew the issued certs +# 11. How to renew the issued certs No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days. @@ -328,7 +348,7 @@ acme.sh --renew -d example.com --force --ecc ``` -# 11. How to upgrade `acme.sh` +# 12. How to upgrade `acme.sh` acme.sh is in constant development, so it's strongly recommended to use the latest code. @@ -353,7 +373,7 @@ acme.sh --upgrade --auto-upgrade 0 ``` -# 12. Issue a cert from an existing CSR +# 13. Issue a cert from an existing CSR https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR diff --git a/acme.sh b/acme.sh index f03501b4..612c2094 100755 --- a/acme.sh +++ b/acme.sh @@ -45,6 +45,8 @@ MODE_STATELESS="stateless" STATE_VERIFIED="verified_ok" +NGINX="nginx:" + BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" END_CSR="-----END CERTIFICATE REQUEST-----" @@ -2277,10 +2279,186 @@ Allow from all return 0 } +#find the real nginx conf file +#backup +#set the nginx conf +#returns the real nginx conf file +_setNginx() { + _d="$1" + _croot="$2" + _thumbpt="$3" + if ! _exists "nginx"; then + _err "nginx command is not found." + return 1 + fi + FOUND_REAL_NGINX_CONF="" + BACKUP_NGINX_CONF="" + _debug _croot "$_croot" + _start_f="$(echo "$_croot" | cut -d : -f 2)" + _debug _start_f "$_start_f" + if [ -z "$_start_f" ]; then + _debug "find start conf from nginx command" + if [ -z "$NGINX_CONF" ]; then + NGINX_CONF="$(nginx -V 2>&1 | _egrep_o "--conf-path=[^ ]* " | tr -d " ")" + _debug NGINX_CONF "$NGINX_CONF" + NGINX_CONF="$(echo "$NGINX_CONF" | cut -d = -f 2)" + _debug NGINX_CONF "$NGINX_CONF" + if [ ! -f "$NGINX_CONF" ]; then + _err "'$NGINX_CONF' doesn't exist." + NGINX_CONF="" + return 1 + fi + _debug "Found nginx conf file:$NGINX_CONF" + fi + _start_f="$NGINX_CONF" + fi + _info "Start detect nginx conf for $_d from:$_start_f" + if ! _checkConf "$_d" "$_start_f"; then + "Can not find conf file for domain $d" + return 1 + fi + _info "Found conf file: $FOUND_REAL_NGINX_CONF" + + mkdir -p "$DOMAIN_BACKUP_PATH" + _backup_conf="$DOMAIN_BACKUP_PATH/$_d.nginx.conf" + _debug _backup_conf "$_backup_conf" + BACKUP_NGINX_CONF="$_backup_conf" + _info "Backup $FOUND_REAL_NGINX_CONF to $_backup_conf" + if ! cp "$FOUND_REAL_NGINX_CONF" "$_backup_conf"; then + _err "backup error." + FOUND_REAL_NGINX_CONF="" + return 1 + fi + + _info "Check the nginx conf before setting up." + if ! _exec "nginx -t" >/dev/null; then + _exec_err + return 1 + fi + + _info "OK, Set up nginx config file" + _ln=$(grep -n "^ *server_name.* $_d" "$_backup_conf" | cut -d : -f 1 | tr -d "\n") + _debug "_ln" "$_ln" + + if ! sed -n "1,${_ln}p" "$_backup_conf" > "$FOUND_REAL_NGINX_CONF"; then + cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + _err "write nginx conf error, but don't worry, the file is restored to the original version." + return 1 + fi + + echo " +location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { + default_type text/plain; + return 200 \"\$1.$_thumbpt\"; +} +" >> "$FOUND_REAL_NGINX_CONF" + + _ln=$(_math $_ln + 1) + if ! sed -n "${_ln},99999p" "$_backup_conf" >> "$FOUND_REAL_NGINX_CONF"; then + cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + _err "write nginx conf error, but don't worry, the file is restored." + return 1 + fi + + _info "nginx conf is done, let's check it again." + if ! _exec "nginx -t" >/dev/null; then + _exec_err + _err "It seems that nginx conf was broken, let's restore." + cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + return 1 + fi + + _info "Reload nginx" + if ! _exec "nginx -s reload" >/dev/null; then + _exec_err + _err "It seems that nginx reload error, let's restore." + cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + return 1 + fi + + return 0 +} + +#d , conf +_checkConf() { + _d="$1" + _c_file="$2" + _debug "Start _checkConf from:$_c_file" + if [ ! -f "$2" ] && ! echo "$2" | grep '*$' >/dev/null && echo "$2" | grep '*' >/dev/null; then + _debug "wildcard" + for _w_f in $2; do + if _checkConf "$1" "$_w_f"; then + return 0 + fi + done + #not found + return 1 + elif [ -f "$2" ]; then + _debug "single" + if _isRealNginxConf "$1" "$2"; then + _debug "$2 is found." + FOUND_REAL_NGINX_CONF="$2" + return 0 + fi + if grep "^ *include *.*;" "$2" >/dev/null; then + _debug "Try include files" + for included in $(grep "^ *include *.*;" "$2"| sed "s/include //" | tr -d " ;" ); do + _debug "check included $included" + if _checkConf "$1" "$included"; then + return 0 + fi + done + fi + return 1 + else + _debug "$2 not found." + return 1 + fi + return 1 +} + +#d , conf +_isRealNginxConf() { + _debug "_isRealNginxConf $1 $2" + if [ -f "$2" ] && grep "^ *server_name " "$2" | grep " $1" >/dev/null; then + return 0 + else + return 1 + fi +} + +#restore all the nginx conf +_restoreNginx() { + if [ -z "$NGINX_VLIST" ]; then + _debug "No need to restore nginx, skip." + return + fi + _debug "_restoreNginx" + _debug "NGINX_VLIST" "$NGINX_VLIST" + + for ng_entry in $(echo "$NGINX_VLIST" | tr "$dvsep" ' '); do + _debug "ng_entry" "$ng_entry" + _nd=$(echo "$ng_entry" | cut -d "$sep" -f 1) + _ngconf=$(echo "$ng_entry" | cut -d "$sep" -f 2) + _ngbackupconf=$(echo "$ng_entry" | cut -d "$sep" -f 3) + _info "Restoring from $_ngbackupconf to $_ngconf" + cat "$_ngbackupconf" > "$_ngconf" + done + + _info "Reload nginx" + if ! _exec "nginx -s reload" >/dev/null; then + _exec_err + _err "It seems that nginx reload error, please report bug." + return 1 + fi + return 0 +} + _clearup() { _stopserver "$serverproc" serverproc="" _restoreApache + _restoreNginx _clearupdns if [ -z "$DEBUG" ]; then rm -f "$TLS_CONF" @@ -2822,6 +3000,7 @@ issue() { _info "Getting domain auth token for each domain" sep='#' + dvsep=',' if [ -z "$vlist" ]; then alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ') _index=1 @@ -2829,7 +3008,7 @@ issue() { for d in $alldomains; do _info "Getting webroot for domain" "$d" _w="$(echo $Le_Webroot | cut -d , -f $_index)" - _info _w "$_w" + _debug _w "$_w" if [ "$_w" ]; then _currentRoot="$_w" fi @@ -2881,13 +3060,13 @@ issue() { dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot" _debug dvlist "$dvlist" - vlist="$vlist$dvlist," + vlist="$vlist$dvlist$dvsep" done - + _debug vlist "$vlist" #add entry dnsadded="" - ventries=$(echo "$vlist" | tr ',' ' ') + ventries=$(echo "$vlist" | tr "$dvsep" ' ') for ventry in $ventries; do d=$(echo "$ventry" | cut -d "$sep" -f 1) keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) @@ -2970,10 +3149,11 @@ issue() { _sleep "$Le_DNSSleep" fi + NGINX_VLIST="" _debug "ok, let's start to verify" _ncIndex=1 - ventries=$(echo "$vlist" | tr ',' ' ') + ventries=$(echo "$vlist" | tr "$dvsep" ' ') for ventry in $ventries; do d=$(echo "$ventry" | cut -d "$sep" -f 1) keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) @@ -3012,6 +3192,22 @@ issue() { elif [ "$_currentRoot" = "$MODE_STATELESS" ]; then _info "Stateless mode for domain:$d" _sleep 1 + elif _startswith "$_currentRoot" "$NGINX"; then + _info "Nginx mode for domain:$d" + #set up nginx server + FOUND_REAL_NGINX_CONF="" + BACKUP_NGINX_CONF="" + if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then + _clearup + _on_issue_err + return 1 + else + _realConf="$FOUND_REAL_NGINX_CONF" + _backup="$BACKUP_NGINX_CONF" + _debug _realConf "$_realConf" + NGINX_VLIST="$NGINX_VLIST$d$sep$_realConf$sep$_backup$dvsep" + fi + _sleep 1 else if [ "$_currentRoot" = "apache" ]; then wellknown_path="$ACME_DIR" @@ -4629,6 +4825,14 @@ _process() { _webroot="$_webroot,$wvalue" fi ;; + --nginx) + wvalue="$NGINX" + if [ -z "$_webroot" ]; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; --tls) wvalue="$W_TLS" if [ -z "$_webroot" ]; then From 03f8d6e946d642c529927668c078df2025f7aa22 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 14 Feb 2017 22:03:48 +0800 Subject: [PATCH 156/620] fix https://github.com/Neilpang/acme.sh/issues/615 --- acme.sh | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index 612c2094..349e1b39 100755 --- a/acme.sh +++ b/acme.sh @@ -46,6 +46,8 @@ MODE_STATELESS="stateless" STATE_VERIFIED="verified_ok" NGINX="nginx:" +NGINX_START="#ACME_NGINX_START" +NGINX_END="#ACME_NGINX_END" BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" END_CSR="-----END CERTIFICATE REQUEST-----" @@ -2312,13 +2314,26 @@ _setNginx() { fi _start_f="$NGINX_CONF" fi - _info "Start detect nginx conf for $_d from:$_start_f" + _debug "Start detect nginx conf for $_d from:$_start_f" if ! _checkConf "$_d" "$_start_f"; then "Can not find conf file for domain $d" return 1 fi _info "Found conf file: $FOUND_REAL_NGINX_CONF" + _ln=$(grep -n "^ *server_name.* $_d" "$FOUND_REAL_NGINX_CONF" | cut -d : -f 1 | tr -d "\n") + _debug "_ln" "$_ln" + + _lnn=$(_math $_ln + 1) + _debug _lnn "$_lnn" + _start_tag="$(sed -n "$_lnn,${_lnn}p" "$FOUND_REAL_NGINX_CONF")" + _debug "_start_tag" "$_start_tag" + if [ "$_start_tag" = "$NGINX_START" ]; then + _info "The domain $_d is already configured, skip" + FOUND_REAL_NGINX_CONF="" + return 0 + fi + mkdir -p "$DOMAIN_BACKUP_PATH" _backup_conf="$DOMAIN_BACKUP_PATH/$_d.nginx.conf" _debug _backup_conf "$_backup_conf" @@ -2337,25 +2352,23 @@ _setNginx() { fi _info "OK, Set up nginx config file" - _ln=$(grep -n "^ *server_name.* $_d" "$_backup_conf" | cut -d : -f 1 | tr -d "\n") - _debug "_ln" "$_ln" if ! sed -n "1,${_ln}p" "$_backup_conf" > "$FOUND_REAL_NGINX_CONF"; then - cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" _err "write nginx conf error, but don't worry, the file is restored to the original version." return 1 fi - echo " + echo "$NGINX_START location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { default_type text/plain; return 200 \"\$1.$_thumbpt\"; } -" >> "$FOUND_REAL_NGINX_CONF" +#NGINX_START +" >>"$FOUND_REAL_NGINX_CONF" - _ln=$(_math $_ln + 1) - if ! sed -n "${_ln},99999p" "$_backup_conf" >> "$FOUND_REAL_NGINX_CONF"; then - cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + if ! sed -n "${_lnn},99999p" "$_backup_conf" >>"$FOUND_REAL_NGINX_CONF"; then + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" _err "write nginx conf error, but don't worry, the file is restored." return 1 fi @@ -2364,7 +2377,7 @@ location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { if ! _exec "nginx -t" >/dev/null; then _exec_err _err "It seems that nginx conf was broken, let's restore." - cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" return 1 fi @@ -2372,7 +2385,7 @@ location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { if ! _exec "nginx -s reload" >/dev/null; then _exec_err _err "It seems that nginx reload error, let's restore." - cat "$_backup_conf" > "$FOUND_REAL_NGINX_CONF" + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" return 1 fi @@ -3201,7 +3214,9 @@ issue() { _clearup _on_issue_err return 1 - else + fi + + if [ "$FOUND_REAL_NGINX_CONF" ]; then _realConf="$FOUND_REAL_NGINX_CONF" _backup="$BACKUP_NGINX_CONF" _debug _realConf "$_realConf" From 5d943a35f8341660c0429e11ea5299bfb008689d Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 14 Feb 2017 22:12:58 +0800 Subject: [PATCH 157/620] fix https://github.com/Neilpang/acme.sh/issues/616 --- acme.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 349e1b39..6234500e 100755 --- a/acme.sh +++ b/acme.sh @@ -2442,14 +2442,14 @@ _isRealNginxConf() { #restore all the nginx conf _restoreNginx() { - if [ -z "$NGINX_VLIST" ]; then + if [ -z "$NGINX_RESTORE_VLIST" ]; then _debug "No need to restore nginx, skip." return fi _debug "_restoreNginx" - _debug "NGINX_VLIST" "$NGINX_VLIST" + _debug "NGINX_RESTORE_VLIST" "$NGINX_RESTORE_VLIST" - for ng_entry in $(echo "$NGINX_VLIST" | tr "$dvsep" ' '); do + for ng_entry in $(echo "$NGINX_RESTORE_VLIST" | tr "$dvsep" ' '); do _debug "ng_entry" "$ng_entry" _nd=$(echo "$ng_entry" | cut -d "$sep" -f 1) _ngconf=$(echo "$ng_entry" | cut -d "$sep" -f 2) @@ -3162,7 +3162,7 @@ issue() { _sleep "$Le_DNSSleep" fi - NGINX_VLIST="" + NGINX_RESTORE_VLIST="" _debug "ok, let's start to verify" _ncIndex=1 @@ -3220,7 +3220,7 @@ issue() { _realConf="$FOUND_REAL_NGINX_CONF" _backup="$BACKUP_NGINX_CONF" _debug _realConf "$_realConf" - NGINX_VLIST="$NGINX_VLIST$d$sep$_realConf$sep$_backup$dvsep" + NGINX_RESTORE_VLIST="$d$sep$_realConf$sep$_backup$dvsep$NGINX_RESTORE_VLIST" fi _sleep 1 else From 302c41edc9c8696f8f266352449eb7e8e2c79533 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 14 Feb 2017 22:41:34 +0800 Subject: [PATCH 158/620] fix format --- acme.sh | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index 6234500e..6121224f 100755 --- a/acme.sh +++ b/acme.sh @@ -2353,7 +2353,7 @@ _setNginx() { _info "OK, Set up nginx config file" - if ! sed -n "1,${_ln}p" "$_backup_conf" > "$FOUND_REAL_NGINX_CONF"; then + if ! sed -n "1,${_ln}p" "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"; then cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" _err "write nginx conf error, but don't worry, the file is restored to the original version." return 1 @@ -2377,7 +2377,7 @@ location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { if ! _exec "nginx -t" >/dev/null; then _exec_err _err "It seems that nginx conf was broken, let's restore." - cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" return 1 fi @@ -2385,7 +2385,7 @@ location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { if ! _exec "nginx -s reload" >/dev/null; then _exec_err _err "It seems that nginx reload error, let's restore." - cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" return 1 fi @@ -2415,7 +2415,7 @@ _checkConf() { fi if grep "^ *include *.*;" "$2" >/dev/null; then _debug "Try include files" - for included in $(grep "^ *include *.*;" "$2"| sed "s/include //" | tr -d " ;" ); do + for included in $(grep "^ *include *.*;" "$2" | sed "s/include //" | tr -d " ;"); do _debug "check included $included" if _checkConf "$1" "$included"; then return 0 @@ -2433,11 +2433,17 @@ _checkConf() { #d , conf _isRealNginxConf() { _debug "_isRealNginxConf $1 $2" - if [ -f "$2" ] && grep "^ *server_name " "$2" | grep " $1" >/dev/null; then + if [ -f "$2" ]; then + for _fln in $(grep -n "^ *server_name.* $1" "$2" | cut -d : -f 1); do + _debug _fln "$_fln" + if [ "$_fln" ]; then + _listen=$(cat "$2" | _head_n "$_fln" | grep "^ *listen .*" | _tail_n 1) + fi + done return 0 - else - return 1 fi + + return 1 } #restore all the nginx conf @@ -2455,7 +2461,7 @@ _restoreNginx() { _ngconf=$(echo "$ng_entry" | cut -d "$sep" -f 2) _ngbackupconf=$(echo "$ng_entry" | cut -d "$sep" -f 3) _info "Restoring from $_ngbackupconf to $_ngconf" - cat "$_ngbackupconf" > "$_ngconf" + cat "$_ngbackupconf" >"$_ngconf" done _info "Reload nginx" @@ -3215,7 +3221,7 @@ issue() { _on_issue_err return 1 fi - + if [ "$FOUND_REAL_NGINX_CONF" ]; then _realConf="$FOUND_REAL_NGINX_CONF" _backup="$BACKUP_NGINX_CONF" From 9f90618a707750475604f5ad8bf726f62f281c67 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 14 Feb 2017 23:57:00 +0800 Subject: [PATCH 159/620] fix https://github.com/Neilpang/acme.sh/issues/617 --- acme.sh | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 6121224f..a846b97a 100755 --- a/acme.sh +++ b/acme.sh @@ -2294,6 +2294,7 @@ _setNginx() { return 1 fi FOUND_REAL_NGINX_CONF="" + FOUND_REAL_NGINX_CONF_LN="" BACKUP_NGINX_CONF="" _debug _croot "$_croot" _start_f="$(echo "$_croot" | cut -d : -f 2)" @@ -2321,7 +2322,7 @@ _setNginx() { fi _info "Found conf file: $FOUND_REAL_NGINX_CONF" - _ln=$(grep -n "^ *server_name.* $_d" "$FOUND_REAL_NGINX_CONF" | cut -d : -f 1 | tr -d "\n") + _ln=$FOUND_REAL_NGINX_CONF_LN _debug "_ln" "$_ln" _lnn=$(_math $_ln + 1) @@ -2437,12 +2438,36 @@ _isRealNginxConf() { for _fln in $(grep -n "^ *server_name.* $1" "$2" | cut -d : -f 1); do _debug _fln "$_fln" if [ "$_fln" ]; then - _listen=$(cat "$2" | _head_n "$_fln" | grep "^ *listen .*" | _tail_n 1) + _start=$(cat "$2" | _head_n "$_fln" | grep -n "^ *server *{" | _tail_n 1) + _debug "_start" "$_start" + _start_n=$(echo "$_start" | cut -d : -f 1) + _start_nn=$(_math $_start_n + 1) + _debug "_start_n" "$_start_n" + _debug "_start_nn" "$_start_nn" + + _left="$(sed -n "${_start_nn},99999p" "$2")" + _debug2 _left "$_left" + if echo "$_left" | grep -n "^ *server *{" >/dev/null; then + _end=$(echo "$_left" | grep -n "^ *server *{" | _head_n 1) + _debug "_end" "$_end" + _end_n=$(echo "$_end" | cut -d : -f 1) + _debug "_end_n" "$_end_n" + _seg_n=$(echo "$_left" | sed -n "1,${_end_n}p") + else + _seg_n="$_left" + fi + + _debug "_seg_n" "$_seg_n" + + if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ]; then + _debug "ssl on, skip" + return 1 + fi + FOUND_REAL_NGINX_CONF_LN=$_fln + return 0 fi done - return 0 fi - return 1 } From 6921211461a1c4d7d24c21643ead5d56d15ea532 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 15 Feb 2017 20:24:24 +0800 Subject: [PATCH 160/620] fix debug message --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index a846b97a..5e84eeaa 100755 --- a/acme.sh +++ b/acme.sh @@ -2528,7 +2528,7 @@ _clearupdns() { txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" _debug txt "$txt" if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then - _info "$d is already verified, skip $vtype." + _debug "$d is already verified, skip $vtype." continue fi @@ -3096,7 +3096,7 @@ issue() { _debug keyauthorization "$keyauthorization" if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then - _info "$d is already verified, skip." + _debug "$d is already verified, skip." keyauthorization="$STATE_VERIFIED" _debug keyauthorization "$keyauthorization" fi @@ -3118,7 +3118,7 @@ issue() { _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then - _info "$d is already verified, skip $vtype." + _debug "$d is already verified, skip $vtype." continue fi From 7db28745c89b168d55b26ab68d696b069d091c23 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 15 Feb 2017 20:28:50 +0800 Subject: [PATCH 161/620] start v2.6.7 --- README.md | 2 +- acme.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index edc4555c..2624690a 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ https://github.com/Neilpang/acmetest - Webroot mode - Standalone mode - Apache mode -- Nginx mode +- Nginx mode ( Beta ) - DNS mode - [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode) diff --git a/acme.sh b/acme.sh index 5e84eeaa..7a229eb6 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.6 +VER=2.6.7 PROJECT_NAME="acme.sh" From 72af092cc1ac37908954366edf3abf05d7fae4be Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 15 Feb 2017 21:09:01 +0800 Subject: [PATCH 162/620] fix https://github.com/Neilpang/acme.sh/issues/614 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 7a229eb6..36443e39 100755 --- a/acme.sh +++ b/acme.sh @@ -994,7 +994,7 @@ _readKeyLengthFromCSR() { echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' else _debug "RSA CSR" - echo "$_outcsr" | _egrep_o "^ *Public-Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 + echo "$_outcsr" | _egrep_o "^ *Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 fi } From ad153ae041f40c4c4d730f35d9e58700ccd25906 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 16 Feb 2017 22:29:08 +0800 Subject: [PATCH 163/620] fix https://github.com/Neilpang/acme.sh/issues/622 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 36443e39..cf9d8501 100755 --- a/acme.sh +++ b/acme.sh @@ -1610,14 +1610,14 @@ _setopt() { __val="$(echo "$__val" | sed 's/&/\\&/g')" fi text="$(cat "$__conf")" - echo "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" + printf -- "%s" "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" elif grep -n "^#$__opt$__sep" "$__conf" >/dev/null; then if _contains "$__val" "&"; then __val="$(echo "$__val" | sed 's/&/\\&/g')" fi text="$(cat "$__conf")" - echo "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" + printf -- "%s" "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" else _debug3 APP From 52f8b787c981ffc761694ad979d58b86390ca9f5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 16 Feb 2017 22:37:32 +0800 Subject: [PATCH 164/620] fix https://github.com/Neilpang/acme.sh/issues/622 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index cf9d8501..a590d10e 100755 --- a/acme.sh +++ b/acme.sh @@ -1610,14 +1610,14 @@ _setopt() { __val="$(echo "$__val" | sed 's/&/\\&/g')" fi text="$(cat "$__conf")" - printf -- "%s" "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" + printf -- "%s\n" "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" elif grep -n "^#$__opt$__sep" "$__conf" >/dev/null; then if _contains "$__val" "&"; then __val="$(echo "$__val" | sed 's/&/\\&/g')" fi text="$(cat "$__conf")" - printf -- "%s" "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" + printf -- "%s\n" "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" else _debug3 APP From 0bc745f68fa9ca0dbb5350bf51ea65f3865824a9 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 17 Feb 2017 13:51:17 +0800 Subject: [PATCH 165/620] retry if nonce is invalid fix https://github.com/Neilpang/acme.sh/issues/627 --- acme.sh | 99 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 43 deletions(-) diff --git a/acme.sh b/acme.sh index a590d10e..d3d3d507 100755 --- a/acme.sh +++ b/acme.sh @@ -1530,62 +1530,75 @@ _send_signed_request() { payload64=$(printf "%s" "$payload" | _base64 | _url_replace) _debug3 payload64 "$payload64" - if [ -z "$_CACHED_NONCE" ]; then - _debug2 "Get nonce." - nonceurl="$API/directory" - _headers="$(_get "$nonceurl" "onlyheader")" + MAX_REQUEST_RETRY_TIMES=5 + _request_retry_times=0 + while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do + _debug3 _request_retry_times "$_request_retry_times" + if [ -z "$_CACHED_NONCE" ]; then + _debug2 "Get nonce." + nonceurl="$API/directory" + _headers="$(_get "$nonceurl" "onlyheader")" - if [ "$?" != "0" ]; then - _err "Can not connect to $nonceurl to get nonce." - return 1 - fi + if [ "$?" != "0" ]; then + _err "Can not connect to $nonceurl to get nonce." + return 1 + fi - _debug2 _headers "$_headers" + _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 - nonce="$_CACHED_NONCE" - _debug2 nonce "$nonce" + _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 + nonce="$_CACHED_NONCE" + _debug2 nonce "$nonce" - protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" - _debug3 protected "$protected" + protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" + _debug3 protected "$protected" - protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" - _debug3 protected64 "$protected64" + protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" + _debug3 protected64 "$protected64" - if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then - _err "Sign request failed." - return 1 - fi - _debug3 _sig_t "$_sig_t" + if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then + _err "Sign request failed." + return 1 + fi + _debug3 _sig_t "$_sig_t" - sig="$(printf "%s" "$_sig_t" | _url_replace)" - _debug3 sig "$sig" + sig="$(printf "%s" "$_sig_t" | _url_replace)" + _debug3 sig "$sig" - body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" - _debug3 body "$body" + body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" + _debug3 body "$body" - response="$(_post "$body" "$url" "$needbase64")" - _CACHED_NONCE="" - if [ "$?" != "0" ]; then - _err "Can not post to $url" - return 1 - fi - _debug2 original "$response" + response="$(_post "$body" "$url" "$needbase64")" + _CACHED_NONCE="" + + if [ "$?" != "0" ]; then + _err "Can not post to $url" + return 1 + fi + _debug2 original "$response" + response="$(echo "$response" | _normalizeJson)" - response="$(echo "$response" | _normalizeJson)" + responseHeaders="$(< "$HTTP_HEADER")" - 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" - _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)" - _CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + if _contains "$response" "JWS has invalid anti-replay nonce"; then + _info "It seems the CA server is busy now, let's wait and retry." + _request_retry_times=$(_math "$_request_retry_times" + 1) + _sleep 5 + continue + fi + break; + done } From b7924ce58b09927c606615b7a485d6870073d0b0 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 17 Feb 2017 14:40:58 +0800 Subject: [PATCH 166/620] fix format --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index d3d3d507..7eee2909 100755 --- a/acme.sh +++ b/acme.sh @@ -1533,7 +1533,7 @@ _send_signed_request() { MAX_REQUEST_RETRY_TIMES=5 _request_retry_times=0 while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do - _debug3 _request_retry_times "$_request_retry_times" + _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then _debug2 "Get nonce." nonceurl="$API/directory" @@ -1582,7 +1582,7 @@ _send_signed_request() { _debug2 original "$response" response="$(echo "$response" | _normalizeJson)" - responseHeaders="$(< "$HTTP_HEADER")" + responseHeaders="$(<"$HTTP_HEADER")" _debug2 responseHeaders "$responseHeaders" _debug2 response "$response" @@ -1597,7 +1597,7 @@ _send_signed_request() { _sleep 5 continue fi - break; + break done } From c70432996a70c82bdb4af526496bbc9b33408ab3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 17 Feb 2017 23:06:39 +0800 Subject: [PATCH 167/620] compatible to openssl 0.9 for hmac function --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 7eee2909..d36df7f7 100755 --- a/acme.sh +++ b/acme.sh @@ -740,9 +740,9 @@ _hmac() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then if [ "$outputhex" ]; then - $OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" | cut -d = -f 2 | tr -d ' ' + ($OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || $OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' ' else - $OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary + $OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || $OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary fi else _err "$alg is not supported yet" From 64802502217e4a4f8694b5e851d83c804b2a2688 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 18 Feb 2017 10:31:18 +0800 Subject: [PATCH 168/620] fix for freebsd --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d36df7f7..aaf966cb 100755 --- a/acme.sh +++ b/acme.sh @@ -1582,7 +1582,7 @@ _send_signed_request() { _debug2 original "$response" response="$(echo "$response" | _normalizeJson)" - responseHeaders="$(<"$HTTP_HEADER")" + responseHeaders="$(cat "$HTTP_HEADER")" _debug2 responseHeaders "$responseHeaders" _debug2 response "$response" From db5046292075d0988031f33105a062d055c84182 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 18 Feb 2017 12:03:21 +0800 Subject: [PATCH 169/620] minor use interactive _sleep --- dnsapi/dns_gd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gd.sh b/dnsapi/dns_gd.sh index 1abeeacf..f2dd1fd5 100755 --- a/dnsapi/dns_gd.sh +++ b/dnsapi/dns_gd.sh @@ -40,7 +40,7 @@ dns_gd_add() { if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[{\"data\":\"$txtvalue\"}]"; then if [ "$response" = "{}" ]; then _info "Added, sleeping 10 seconds" - sleep 10 + _sleep 10 #todo: check if the record takes effect return 0 else From fc6cf4d9635544a8f8e6d6d1a6c33254cf16c537 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 12:13:18 +0800 Subject: [PATCH 170/620] fix syslog --- acme.sh | 69 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/acme.sh b/acme.sh index aaf966cb..34ca1d9d 100755 --- a/acme.sh +++ b/acme.sh @@ -65,10 +65,31 @@ LOG_LEVEL_2=2 LOG_LEVEL_3=3 DEFAULT_LOG_LEVEL="$LOG_LEVEL_1" -SYSLOG_INFO="user.info" +DEBUG_LEVEL_1=1 +DEBUG_LEVEL_2=2 +DEBUG_LEVEL_3=3 +DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1 +DEBUG_LEVEL_NONE=0 + SYSLOG_ERROR="user.error" +SYSLOG_INFO="user.info" SYSLOG_DEBUG="user.debug" +#error +SYSLOG_LEVEL_1=1 +#info +SYSLOG_LEVEL_2=2 +#debug +SYSLOG_LEVEL_3=3 +#debug2 +SYSLOG_LEVEL_4=4 +#debug3 +SYSLOG_LEVEL_5=5 + +SYSLOG_LEVEL_DEFAULT=$SYSLOG_LEVEL_1 +#none +SYSLOG_LEVEL_NONE=0 + _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" @@ -138,7 +159,7 @@ _dlg_versions() { #class _syslog() { - if [ -z "$SYS_LOG" ] || [ "$SYS_LOG" = "0" ]; then + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" = "$SYSLOG_LEVEL_NONE" ]; then return fi _logclass="$1" @@ -147,19 +168,21 @@ _syslog() { } _log() { - _syslog "$@" [ -z "$LOG_FILE" ] && return - shift _printargs "$@" >>"$LOG_FILE" } _info() { - _log "$SYSLOG_INFO" "$@" + _log "$@" + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_2" ]; then + _syslog "$SYSLOG_INFO" "$@" + fi _printargs "$@" } _err() { - _log "$SYSLOG_ERROR" "$@" + _syslog "$SYSLOG_ERROR" "$@" + _log "$@" if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then printf -- "%s" "[$(date)] " >&2 fi @@ -178,29 +201,37 @@ _usage() { } _debug() { - if [ -z "$LOG_LEVEL" ] || [ "$LOG_LEVEL" -ge "$LOG_LEVEL_1" ]; then - _log "$SYSLOG_DEBUG" "$@" + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then + _log "$@" fi - if [ -z "$DEBUG" ]; then - return + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_3" ]; then + _syslog "$SYSLOG_DEBUG" "$@" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then + _printargs "$@" >&2 fi - _printargs "$@" >&2 } _debug2() { - if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_2" ]; then - _log "$SYSLOG_DEBUG" "$@" + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then + _log "$@" fi - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_4" ]; then + _syslog "$SYSLOG_DEBUG" "$@" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then _printargs "$@" >&2 fi } _debug3() { - if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_3" ]; then - _log "$SYSLOG_DEBUG" "$@" + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then + _log "$@" + fi + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_5" ]; then + _syslog "$SYSLOG_DEBUG" "$@" fi - if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ]; then + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then _printargs "$@" >&2 fi } @@ -4840,7 +4871,7 @@ _process() { ;; --debug) if [ -z "$2" ] || _startswith "$2" "-"; then - DEBUG="1" + DEBUG="$DEBUG_LEVEL_DEFAULT" else DEBUG="$2" shift @@ -5069,7 +5100,7 @@ _process() { shift fi if [ -z "$_syslog" ]; then - _syslog="1" + _syslog="$SYSLOG_LEVEL_DEFAULT" fi ;; --auto-upgrade) From 113089be5d5310e4d8acce352fcbe592a1c5220f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 12:42:37 +0800 Subject: [PATCH 171/620] fix syslog level --- acme.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/acme.sh b/acme.sh index 34ca1d9d..f4ee89c9 100755 --- a/acme.sh +++ b/acme.sh @@ -76,17 +76,17 @@ SYSLOG_INFO="user.info" SYSLOG_DEBUG="user.debug" #error -SYSLOG_LEVEL_1=1 +SYSLOG_LEVEL_ERROR=3 #info -SYSLOG_LEVEL_2=2 +SYSLOG_LEVEL_INFO=6 #debug -SYSLOG_LEVEL_3=3 +SYSLOG_LEVEL_DEBUG=7 #debug2 -SYSLOG_LEVEL_4=4 +SYSLOG_LEVEL_DEBUG_2=8 #debug3 -SYSLOG_LEVEL_5=5 +SYSLOG_LEVEL_DEBUG_3=9 -SYSLOG_LEVEL_DEFAULT=$SYSLOG_LEVEL_1 +SYSLOG_LEVEL_DEFAULT=$SYSLOG_LEVEL_ERROR #none SYSLOG_LEVEL_NONE=0 @@ -174,7 +174,7 @@ _log() { _info() { _log "$@" - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_2" ]; then + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_INFO" ]; then _syslog "$SYSLOG_INFO" "$@" fi _printargs "$@" @@ -204,7 +204,7 @@ _debug() { if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then _log "$@" fi - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_3" ]; then + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then _syslog "$SYSLOG_DEBUG" "$@" fi if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then @@ -216,7 +216,7 @@ _debug2() { if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then _log "$@" fi - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_4" ]; then + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then _syslog "$SYSLOG_DEBUG" "$@" fi if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then @@ -228,7 +228,7 @@ _debug3() { if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then _log "$@" fi - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_5" ]; then + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then _syslog "$SYSLOG_DEBUG" "$@" fi if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then From 52765466c12aaeaff6d7c9c9eab1e18f8cb84042 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 12:55:05 +0800 Subject: [PATCH 172/620] fix syslog doc --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index f4ee89c9..aa9d24b0 100755 --- a/acme.sh +++ b/acme.sh @@ -4596,7 +4596,7 @@ Parameters: --accountkeylength, -ak [2048] Specifies the account key length. --log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here. --log-level 1|2 Specifies the log level, default is 1. - --syslog [1|0] Enable/Disable syslog. + --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: From e6e85b0c556a5458177fd2a4d31cf3d019d6f727 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 13:24:00 +0800 Subject: [PATCH 173/620] secure debug message --- acme.sh | 68 ++++++++++++++++++++++++++++++++++++++++++- dnsapi/dns_aws.sh | 4 +-- dnsapi/dns_lexicon.sh | 8 ++--- dnsapi/dns_ovh.sh | 4 +-- 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index aa9d24b0..a8b0790b 100755 --- a/acme.sh +++ b/acme.sh @@ -71,6 +71,8 @@ DEBUG_LEVEL_3=3 DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1 DEBUG_LEVEL_NONE=0 +HIDDEN_VALUE="[hidden](please add '--output-insecure' to see this value)" + SYSLOG_ERROR="user.error" SYSLOG_INFO="user.info" SYSLOG_DEBUG="user.debug" @@ -212,6 +214,27 @@ _debug() { fi } +#output the sensitive messages +_secure_debug() { + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _log "$@" + else + _log "$1" "$HIDDEN_VALUE" + fi + fi + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then + _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _printargs "$@" >&2 + else + _printargs "$1" "$HIDDEN_VALUE" >&2 + fi + fi +} + _debug2() { if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then _log "$@" @@ -224,6 +247,26 @@ _debug2() { fi } +_secure_debug2() { + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _log "$@" + else + _log "$1" "$HIDDEN_VALUE" + fi + fi + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then + _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _printargs "$@" >&2 + else + _printargs "$1" "$HIDDEN_VALUE" >&2 + fi + fi +} + _debug3() { if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then _log "$@" @@ -236,6 +279,26 @@ _debug3() { fi } +_secure_debug3() { + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _log "$@" + else + _log "$1" "$HIDDEN_VALUE" + fi + fi + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then + _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _printargs "$@" >&2 + else + _printargs "$1" "$HIDDEN_VALUE" >&2 + fi + fi +} + _startswith() { _str="$1" _sub="$2" @@ -4583,7 +4646,7 @@ Parameters: --force, -f Used to force to install or force to renew a cert immediately. --staging, --test Use staging server, just for test. --debug Output debug info. - + --output-insecure Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for secure. --webroot, -w /path/to/webroot Specifies the web root folder for web root mode. --standalone Use standalone mode. --stateless Use stateless mode, see: $_STATELESS_WIKI @@ -4877,6 +4940,9 @@ _process() { shift fi ;; + --output-insecure) + export OUTPUT_INSECURE=1 + ;; --webroot | -w) wvalue="$2" if [ -z "$_webroot" ]; then diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 29d7a2cd..84aa28d3 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -181,10 +181,10 @@ aws_rest() { #kSecret="wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ############################ - _debug2 kSecret "$kSecret" + _secure_debug2 kSecret "$kSecret" kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")" - _debug2 kSecretH "$kSecretH" + _secure_debug2 kSecretH "$kSecretH" kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" _debug2 kDateH "$kDateH" diff --git a/dnsapi/dns_lexicon.sh b/dnsapi/dns_lexicon.sh index c38ff3e3..c09f16fd 100755 --- a/dnsapi/dns_lexicon.sh +++ b/dnsapi/dns_lexicon.sh @@ -34,7 +34,7 @@ dns_lexicon_add() { # shellcheck disable=SC2018,SC2019 Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z') Lx_name_v=$(eval echo \$"$Lx_name") - _debug "$Lx_name" "$Lx_name_v" + _secure_debug "$Lx_name" "$Lx_name_v" if [ "$Lx_name_v" ]; then _saveaccountconf "$Lx_name" "$Lx_name_v" eval export "$Lx_name" @@ -43,7 +43,7 @@ dns_lexicon_add() { # shellcheck disable=SC2018,SC2019 Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z') Lx_token_v=$(eval echo \$"$Lx_token") - _debug "$Lx_token" "$Lx_token_v" + _secure_debug "$Lx_token" "$Lx_token_v" if [ "$Lx_token_v" ]; then _saveaccountconf "$Lx_token" "$Lx_token_v" eval export "$Lx_token" @@ -52,7 +52,7 @@ dns_lexicon_add() { # shellcheck disable=SC2018,SC2019 Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z') Lx_password_v=$(eval echo \$"$Lx_password") - _debug "$Lx_password" "$Lx_password_v" + _secure_debug "$Lx_password" "$Lx_password_v" if [ "$Lx_password_v" ]; then _saveaccountconf "$Lx_password" "$Lx_password_v" eval export "$Lx_password" @@ -61,7 +61,7 @@ dns_lexicon_add() { # shellcheck disable=SC2018,SC2019 Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z') Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken") - _debug "$Lx_domaintoken" "$Lx_domaintoken_v" + _secure_debug "$Lx_domaintoken" "$Lx_domaintoken_v" if [ "$Lx_domaintoken_v" ]; then eval export "$Lx_domaintoken" _saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v" diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 8833c0a1..faf5b42b 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -207,7 +207,7 @@ _ovh_authentication() { _err "Unable to get consumerKey" return 1 fi - _debug consumerKey "$consumerKey" + _secure_debug consumerKey "$consumerKey" OVH_CK="$consumerKey" _saveaccountconf OVH_CK "$OVH_CK" @@ -269,7 +269,7 @@ _ovh_rest() { _ovh_t="$(_ovh_timestamp)" _debug2 _ovh_t "$_ovh_t" _ovh_p="$OVH_AS+$OVH_CK+$m+$_ovh_url+$data+$_ovh_t" - _debug _ovh_p "$_ovh_p" + _secure_debug _ovh_p "$_ovh_p" _ovh_hex="$(printf "%s" "$_ovh_p" | _digest sha1 hex)" _debug2 _ovh_hex "$_ovh_hex" From 43d3b51bdee418732e54d0779da491e9369b836f Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 19 Feb 2017 18:16:12 +0800 Subject: [PATCH 174/620] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2624690a..716abe20 100644 --- a/README.md +++ b/README.md @@ -403,6 +403,6 @@ Please Star and Fork me. # Donate -1. PayPal: donate@acme.sh - +1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/) + [Donate List](https://github.com/Neilpang/acme.sh/wiki/Donate-list) From cb6f62295748a415c55316cb90865a2f3a9bc9e9 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 19 Feb 2017 18:19:24 +0800 Subject: [PATCH 175/620] Update README.md --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 716abe20..a297b998 100644 --- a/README.md +++ b/README.md @@ -378,21 +378,21 @@ acme.sh --upgrade --auto-upgrade 0 https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR -# Under the Hood +# 14. Under the Hood Speak ACME language using shell, directly to "Let's Encrypt". TODO: -# Acknowledgments +# 15. Acknowledgments 1. Acme-tiny: https://github.com/diafygi/acme-tiny 2. ACME protocol: https://github.com/ietf-wg-acme/acme 3. Certbot: https://github.com/certbot/certbot -# License & Others +# 16. License & Others License is GPLv3 @@ -401,7 +401,8 @@ 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. -# Donate +# 17. Donate +Your donation makes **acme.sh** better: 1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/) From 93bce1b24cd1f3af6740ed6a8070a2cd176f8201 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 20:15:00 +0800 Subject: [PATCH 176/620] support multiple deploy hook fix https://github.com/Neilpang/acme.sh/issues/508 --- acme.sh | 90 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 38 deletions(-) diff --git a/acme.sh b/acme.sh index a8b0790b..2086ccc2 100755 --- a/acme.sh +++ b/acme.sh @@ -3693,7 +3693,7 @@ renew() { fi if [ "$Le_DeployHook" ]; then - deploy "$Le_Domain" "$Le_DeployHook" "$Le_Keylength" + _deploy "$Le_Domain" "$Le_DeployHook" res="$?" fi @@ -3865,54 +3865,64 @@ list() { } +_deploy() { + _d="$1" + _hooks="$2" + + for _d_api in $(echo "$_hooks" | tr ',' " "); do + _deployApi="$(_findHook "$_d" deploy "$_d_api")" + if [ -z "$_deployApi" ]; then + _err "The deploy hook $_d_api is not found." + return 1 + fi + _debug _deployApi "$_deployApi" + + if ! ( + if ! . "$_deployApi"; then + _err "Load file $_deployApi error. Please check your api file and try again." + return 1 + fi + + d_command="${_d_api}_deploy" + 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 "$_d" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then + _err "Error deploy for domain:$_d" + return 1 + fi + ); then + _err "Deploy error." + return 1 + else + _info "$(__green Success)" + fi + done +} + +#domain hooks deploy() { - Le_Domain="$1" - Le_DeployHook="$2" + _d="$1" + _hooks="$2" _isEcc="$3" - if [ -z "$Le_DeployHook" ]; then + if [ -z "$_hooks" ]; then _usage "Usage: $PROJECT_ENTRY --deploy -d domain.com --deploy-hook cpanel [--ecc] " return 1 fi - _initpath "$Le_Domain" "$_isEcc" + _initpath "$_d" "$_isEcc" if [ ! -d "$DOMAIN_PATH" ]; then - _err "Domain is not valid:'$Le_Domain'" - return 1 - fi - - _deployApi="$(_findHook "$Le_Domain" deploy "$Le_DeployHook")" - if [ -z "$_deployApi" ]; then - _err "The deploy hook $Le_DeployHook is not found." + _err "Domain is not valid:'$_d'" return 1 fi - _debug _deployApi "$_deployApi" - - _savedomainconf Le_DeployHook "$Le_DeployHook" - if ! ( - if ! . "$_deployApi"; then - _err "Load file $_deployApi error. Please check your api file and try again." - return 1 - fi - - d_command="${Le_DeployHook}_deploy" - 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 + . "$DOMAIN_CONF" - if ! $d_command "$Le_Domain" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then - _err "Error deploy for domain:$Le_Domain" - _on_issue_err - return 1 - fi - ); then - _err "Deploy error." - return 1 - else - _info "$(__green Success)" - fi + _savedomainconf Le_DeployHook "$_hooks" + _deploy "$_d" "$_hooks" } installcert() { @@ -5136,7 +5146,11 @@ _process() { shift ;; --deploy-hook) - _deploy_hook="$2" + if [ -z "$2" ] || _startswith "$2" "-"; then + _usage "Please specify a value for '--deploy-hook'" + return 1 + fi + _deploy_hook="$_deploy_hook$2," shift ;; --ocsp-must-staple | --ocsp) From a6d2e3a1e6b34c1fbf0675401672b76e8925809b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Sun, 19 Feb 2017 13:26:32 +0100 Subject: [PATCH 177/620] Suppress shellcheck warnings. --- dnsapi/dns_cyon.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 0ced4217..c096d8b0 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -81,6 +81,7 @@ _cyon_is_idn() { _cyon_load_parameters() { # Read the required parameters to add the TXT entry. + # shellcheck disable=SC2018,SC2019 fulldomain="$(printf "%s" "${1}" | tr "A-Z" "a-z")" fulldomain_idn="${fulldomain}" From 3a1bd3114b3c965d9718ee5bb039ced856136a65 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 20:35:32 +0800 Subject: [PATCH 178/620] add hooks, not implemented yet. --- deploy/apache.sh | 26 ++++++++++++++++++++++++++ deploy/dovecot.sh | 26 ++++++++++++++++++++++++++ deploy/exim4.sh | 26 ++++++++++++++++++++++++++ deploy/haproxy.sh | 26 ++++++++++++++++++++++++++ deploy/mysqld.sh | 26 ++++++++++++++++++++++++++ deploy/nginx.sh | 26 ++++++++++++++++++++++++++ deploy/opensshd.sh | 26 ++++++++++++++++++++++++++ deploy/pureftpd.sh | 26 ++++++++++++++++++++++++++ deploy/vsftpd.sh | 26 ++++++++++++++++++++++++++ 9 files changed, 234 insertions(+) create mode 100644 deploy/apache.sh create mode 100644 deploy/dovecot.sh create mode 100644 deploy/exim4.sh create mode 100644 deploy/haproxy.sh create mode 100644 deploy/mysqld.sh create mode 100644 deploy/nginx.sh create mode 100644 deploy/opensshd.sh create mode 100644 deploy/pureftpd.sh create mode 100644 deploy/vsftpd.sh diff --git a/deploy/apache.sh b/deploy/apache.sh new file mode 100644 index 00000000..42de93f4 --- /dev/null +++ b/deploy/apache.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to dovecot server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +apache_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "Deploy cert to apache server, Not implemented yet" + return 1 + +} diff --git a/deploy/dovecot.sh b/deploy/dovecot.sh new file mode 100644 index 00000000..99a17d51 --- /dev/null +++ b/deploy/dovecot.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to dovecot server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +dovecot_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "Not implemented yet" + return 1 + +} diff --git a/deploy/exim4.sh b/deploy/exim4.sh new file mode 100644 index 00000000..cc53e344 --- /dev/null +++ b/deploy/exim4.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to exim4 server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +exim4_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to exim4 server, Not implemented yet" + return 1 + +} diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh new file mode 100644 index 00000000..e7fa5b09 --- /dev/null +++ b/deploy/haproxy.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to haproxy server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +haproxy_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to haproxy server, Not implemented yet" + return 1 + +} diff --git a/deploy/mysqld.sh b/deploy/mysqld.sh new file mode 100644 index 00000000..6fb178d7 --- /dev/null +++ b/deploy/mysqld.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to mysqld server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +mysqld_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to mysqld server, Not implemented yet" + return 1 + +} diff --git a/deploy/nginx.sh b/deploy/nginx.sh new file mode 100644 index 00000000..2fb127fd --- /dev/null +++ b/deploy/nginx.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to nginx server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +nginx_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to nginx server, Not implemented yet" + return 1 + +} diff --git a/deploy/opensshd.sh b/deploy/opensshd.sh new file mode 100644 index 00000000..01fbc3f1 --- /dev/null +++ b/deploy/opensshd.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to opensshd server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +opensshd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to opensshd server, Not implemented yet" + return 1 + +} diff --git a/deploy/pureftpd.sh b/deploy/pureftpd.sh new file mode 100644 index 00000000..28643204 --- /dev/null +++ b/deploy/pureftpd.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to pureftpd server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +pureftpd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to pureftpd server, Not implemented yet" + return 1 + +} diff --git a/deploy/vsftpd.sh b/deploy/vsftpd.sh new file mode 100644 index 00000000..7ff1a58a --- /dev/null +++ b/deploy/vsftpd.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to vsftpd server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +vsftpd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to vsftpd server, Not implemented yet" + return 1 + +} From f845b371ceb95c4712405704928d90813d67c591 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 20:40:53 +0800 Subject: [PATCH 179/620] fix format --- deploy/apache.sh | 52 +++++++++++++++++++++++----------------------- deploy/dovecot.sh | 52 +++++++++++++++++++++++----------------------- deploy/exim4.sh | 52 +++++++++++++++++++++++----------------------- deploy/haproxy.sh | 52 +++++++++++++++++++++++----------------------- deploy/mysqld.sh | 52 +++++++++++++++++++++++----------------------- deploy/nginx.sh | 52 +++++++++++++++++++++++----------------------- deploy/opensshd.sh | 52 +++++++++++++++++++++++----------------------- deploy/pureftpd.sh | 52 +++++++++++++++++++++++----------------------- deploy/vsftpd.sh | 52 +++++++++++++++++++++++----------------------- 9 files changed, 234 insertions(+), 234 deletions(-) diff --git a/deploy/apache.sh b/deploy/apache.sh index 42de93f4..b6c1fbc2 100644 --- a/deploy/apache.sh +++ b/deploy/apache.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to dovecot server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -apache_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "Deploy cert to apache server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to dovecot server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +apache_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "Deploy cert to apache server, Not implemented yet" + return 1 + +} diff --git a/deploy/dovecot.sh b/deploy/dovecot.sh index 99a17d51..3baf23d9 100644 --- a/deploy/dovecot.sh +++ b/deploy/dovecot.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to dovecot server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -dovecot_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to dovecot server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +dovecot_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "Not implemented yet" + return 1 + +} diff --git a/deploy/exim4.sh b/deploy/exim4.sh index cc53e344..b53f58ec 100644 --- a/deploy/exim4.sh +++ b/deploy/exim4.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to exim4 server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -exim4_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "deploy cert to exim4 server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to exim4 server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +exim4_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to exim4 server, Not implemented yet" + return 1 + +} diff --git a/deploy/haproxy.sh b/deploy/haproxy.sh index e7fa5b09..34efbb1f 100644 --- a/deploy/haproxy.sh +++ b/deploy/haproxy.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to haproxy server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -haproxy_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "deploy cert to haproxy server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to haproxy server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +haproxy_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to haproxy server, Not implemented yet" + return 1 + +} diff --git a/deploy/mysqld.sh b/deploy/mysqld.sh index 6fb178d7..8778843e 100644 --- a/deploy/mysqld.sh +++ b/deploy/mysqld.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to mysqld server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -mysqld_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "deploy cert to mysqld server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to mysqld server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +mysqld_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to mysqld server, Not implemented yet" + return 1 + +} diff --git a/deploy/nginx.sh b/deploy/nginx.sh index 2fb127fd..952b27f3 100644 --- a/deploy/nginx.sh +++ b/deploy/nginx.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to nginx server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -nginx_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "deploy cert to nginx server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to nginx server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +nginx_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to nginx server, Not implemented yet" + return 1 + +} diff --git a/deploy/opensshd.sh b/deploy/opensshd.sh index 01fbc3f1..9001b97c 100644 --- a/deploy/opensshd.sh +++ b/deploy/opensshd.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to opensshd server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -opensshd_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "deploy cert to opensshd server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to opensshd server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +opensshd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to opensshd server, Not implemented yet" + return 1 + +} diff --git a/deploy/pureftpd.sh b/deploy/pureftpd.sh index 28643204..3d803601 100644 --- a/deploy/pureftpd.sh +++ b/deploy/pureftpd.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to pureftpd server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -pureftpd_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "deploy cert to pureftpd server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to pureftpd server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +pureftpd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to pureftpd server, Not implemented yet" + return 1 + +} diff --git a/deploy/vsftpd.sh b/deploy/vsftpd.sh index 7ff1a58a..5e89ea95 100644 --- a/deploy/vsftpd.sh +++ b/deploy/vsftpd.sh @@ -1,26 +1,26 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to vsftpd server. - -#returns 0 means success, otherwise error. - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -vsftpd_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - _err "deploy cert to vsftpd server, Not implemented yet" - return 1 - -} +#!/usr/bin/env sh + +#Here is a script to deploy cert to vsftpd server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +vsftpd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to vsftpd server, Not implemented yet" + return 1 + +} From af1cc3b3317d7a8ed2f4c65d8b57cb2cf7e75602 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 21:13:00 +0800 Subject: [PATCH 180/620] refactor params --- acme.sh | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/acme.sh b/acme.sh index 2086ccc2..d2910ab3 100755 --- a/acme.sh +++ b/acme.sh @@ -2707,6 +2707,7 @@ _clearupwebbroot() { } _on_before_issue() { + _chk_web_roots="$1" _debug _on_before_issue #run pre hook if [ "$Le_PreHook" ]; then @@ -2719,7 +2720,7 @@ _on_before_issue() { fi fi - if _hasfield "$Le_Webroot" "$NO_VALUE"; then + if _hasfield "$_chk_web_roots" "$NO_VALUE"; then if ! _exists "nc"; then _err "Please install netcat(nc) tools first." return 1 @@ -2734,7 +2735,7 @@ _on_before_issue() { _addrIndex=1 for d in $alldomains; do _debug "Check for domain" "$d" - _currentRoot="$(_getfield "$Le_Webroot" $_index)" + _currentRoot="$(_getfield "$_chk_web_roots" $_index)" _debug "_currentRoot" "$_currentRoot" _index=$(_math $_index + 1) _checkport="" @@ -2777,7 +2778,7 @@ _on_before_issue() { fi done - if _hasfield "$Le_Webroot" "apache"; then + if _hasfield "$_chk_web_roots" "apache"; then if ! _setApache; then _err "set up apache error. Report error to me." return 1 @@ -3027,11 +3028,11 @@ issue() { _usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ " return 1 fi - Le_Webroot="$1" - Le_Domain="$2" + _web_roots="$1" + _main_domain="$2" Le_Alt="$3" - if _contains "$Le_Domain" ","; then - Le_Domain=$(echo "$2,$3" | cut -d , -f 1) + if _contains "$_main_domain" ","; then + _main_domain=$(echo "$2,$3" | cut -d , -f 1) Le_Alt=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") fi Le_Keylength="$4" @@ -3046,19 +3047,19 @@ issue() { Le_LocalAddress="${13}" #remove these later. - if [ "$Le_Webroot" = "dns-cf" ]; then - Le_Webroot="dns_cf" + if [ "$_web_roots" = "dns-cf" ]; then + _web_roots="dns_cf" fi - if [ "$Le_Webroot" = "dns-dp" ]; then - Le_Webroot="dns_dp" + if [ "$_web_roots" = "dns-dp" ]; then + _web_roots="dns_dp" fi - if [ "$Le_Webroot" = "dns-cx" ]; then - Le_Webroot="dns_cx" + if [ "$_web_roots" = "dns-cx" ]; then + _web_roots="dns_cx" fi _debug "Using api: $API" if [ ! "$IS_RENEW" ]; then - _initpath "$Le_Domain" "$Le_Keylength" + _initpath "$_main_domain" "$Le_Keylength" mkdir -p "$DOMAIN_PATH" fi @@ -3070,7 +3071,7 @@ issue() { _debug _saved_domain "$_saved_domain" _saved_alt=$(_readdomainconf Le_Alt) _debug _saved_alt "$_saved_alt" - if [ "$_saved_domain,$_saved_alt" = "$Le_Domain,$Le_Alt" ]; then + if [ "$_saved_domain,$_saved_alt" = "$_main_domain,$Le_Alt" ]; then _info "Domains not changed." _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")" _info "Add '$(__red '--force')' to force to renew." @@ -3081,9 +3082,9 @@ issue() { fi fi - _savedomainconf "Le_Domain" "$Le_Domain" + _savedomainconf "Le_Domain" "$_main_domain" _savedomainconf "Le_Alt" "$Le_Alt" - _savedomainconf "Le_Webroot" "$Le_Webroot" + _savedomainconf "Le_Webroot" "$_web_roots" _savedomainconf "Le_PreHook" "$Le_PreHook" _savedomainconf "Le_PostHook" "$Le_PostHook" @@ -3106,7 +3107,7 @@ issue() { Le_Keylength="" fi - if ! _on_before_issue; then + if ! _on_before_issue "$_web_roots"; then _err "_on_before_issue." return 1 fi @@ -3129,7 +3130,7 @@ issue() { _key=$(_readdomainconf Le_Keylength) _debug "Read key length:$_key" if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ]; then - if ! createDomainKey "$Le_Domain" "$Le_Keylength"; then + if ! createDomainKey "$_main_domain" "$Le_Keylength"; then _err "Create domain key error." _clearup _on_issue_err @@ -3137,7 +3138,7 @@ issue() { fi fi - if ! _createcsr "$Le_Domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then + if ! _createcsr "$_main_domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then _err "Create CSR error." _clearup _on_issue_err @@ -3153,12 +3154,12 @@ issue() { sep='#' dvsep=',' if [ -z "$vlist" ]; then - alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ') + alldomains=$(echo "$_main_domain,$Le_Alt" | tr ',' ' ') _index=1 _currentRoot="" for d in $alldomains; do _info "Getting webroot for domain" "$d" - _w="$(echo $Le_Webroot | cut -d , -f $_index)" + _w="$(echo $_web_roots | cut -d , -f $_index)" _debug _w "$_w" if [ "$_w" ]; then _currentRoot="$_w" From 02140ce763c2f254674def89ee63ab9b5bbc4feb Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 21:18:00 +0800 Subject: [PATCH 181/620] refactor alt domains --- acme.sh | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/acme.sh b/acme.sh index d2910ab3..30bb0585 100755 --- a/acme.sh +++ b/acme.sh @@ -2708,6 +2708,8 @@ _clearupwebbroot() { _on_before_issue() { _chk_web_roots="$1" + _chk_main_domain="$2" + _chk_alt_domains="$3" _debug _on_before_issue #run pre hook if [ "$Le_PreHook" ]; then @@ -2729,7 +2731,7 @@ _on_before_issue() { _debug Le_LocalAddress "$Le_LocalAddress" - alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ') + alldomains=$(echo "$_chk_main_domain,$_chk_alt_domains" | tr ',' ' ') _index=1 _currentRoot="" _addrIndex=1 @@ -3030,10 +3032,10 @@ issue() { fi _web_roots="$1" _main_domain="$2" - Le_Alt="$3" + _alt_domains="$3" if _contains "$_main_domain" ","; then _main_domain=$(echo "$2,$3" | cut -d , -f 1) - Le_Alt=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") + _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") fi Le_Keylength="$4" Le_RealCertPath="$5" @@ -3071,7 +3073,7 @@ issue() { _debug _saved_domain "$_saved_domain" _saved_alt=$(_readdomainconf Le_Alt) _debug _saved_alt "$_saved_alt" - if [ "$_saved_domain,$_saved_alt" = "$_main_domain,$Le_Alt" ]; then + if [ "$_saved_domain,$_saved_alt" = "$_main_domain,$_alt_domains" ]; then _info "Domains not changed." _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")" _info "Add '$(__red '--force')' to force to renew." @@ -3083,7 +3085,7 @@ issue() { fi _savedomainconf "Le_Domain" "$_main_domain" - _savedomainconf "Le_Alt" "$Le_Alt" + _savedomainconf "Le_Alt" "$_alt_domains" _savedomainconf "Le_Webroot" "$_web_roots" _savedomainconf "Le_PreHook" "$Le_PreHook" @@ -3099,15 +3101,15 @@ issue() { Le_API="$API" _savedomainconf "Le_API" "$Le_API" - if [ "$Le_Alt" = "$NO_VALUE" ]; then - Le_Alt="" + if [ "$_alt_domains" = "$NO_VALUE" ]; then + _alt_domains="" fi if [ "$Le_Keylength" = "$NO_VALUE" ]; then Le_Keylength="" fi - if ! _on_before_issue "$_web_roots"; then + if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains"; then _err "_on_before_issue." return 1 fi @@ -3138,7 +3140,7 @@ issue() { fi fi - if ! _createcsr "$_main_domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then + if ! _createcsr "$_main_domain" "$_alt_domains" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then _err "Create CSR error." _clearup _on_issue_err @@ -3154,7 +3156,7 @@ issue() { sep='#' dvsep=',' if [ -z "$vlist" ]; then - alldomains=$(echo "$_main_domain,$Le_Alt" | tr ',' ' ') + alldomains=$(echo "$_main_domain,$_alt_domains" | tr ',' ' ') _index=1 _currentRoot="" for d in $alldomains; do From d9c9114b3b897dcedd4c6a77f5dd03a346caec06 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 21:21:11 +0800 Subject: [PATCH 182/620] refactor key length --- acme.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index 30bb0585..a9f9e72c 100755 --- a/acme.sh +++ b/acme.sh @@ -3037,7 +3037,7 @@ issue() { _main_domain=$(echo "$2,$3" | cut -d , -f 1) _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") fi - Le_Keylength="$4" + _key_length="$4" Le_RealCertPath="$5" Le_RealKeyPath="$6" Le_RealCACertPath="$7" @@ -3061,7 +3061,7 @@ issue() { _debug "Using api: $API" if [ ! "$IS_RENEW" ]; then - _initpath "$_main_domain" "$Le_Keylength" + _initpath "$_main_domain" "$_key_length" mkdir -p "$DOMAIN_PATH" fi @@ -3105,8 +3105,8 @@ issue() { _alt_domains="" fi - if [ "$Le_Keylength" = "$NO_VALUE" ]; then - Le_Keylength="" + if [ "$_key_length" = "$NO_VALUE" ]; then + _key_length="" fi if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains"; then @@ -3131,8 +3131,8 @@ issue() { else _key=$(_readdomainconf Le_Keylength) _debug "Read key length:$_key" - if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ]; then - if ! createDomainKey "$_main_domain" "$Le_Keylength"; then + if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ]; then + if ! createDomainKey "$_main_domain" "$_key_length"; then _err "Create domain key error." _clearup _on_issue_err @@ -3148,7 +3148,7 @@ issue() { fi fi - _savedomainconf "Le_Keylength" "$Le_Keylength" + _savedomainconf "Le_Keylength" "$_key_length" vlist="$Le_Vlist" From 85e1f4ea13f2fa5a754bf6c65795c03da84f2584 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 19 Feb 2017 22:09:22 +0800 Subject: [PATCH 183/620] refactor parameters --- acme.sh | 227 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 120 insertions(+), 107 deletions(-) diff --git a/acme.sh b/acme.sh index a9f9e72c..db77c226 100755 --- a/acme.sh +++ b/acme.sh @@ -2710,12 +2710,14 @@ _on_before_issue() { _chk_web_roots="$1" _chk_main_domain="$2" _chk_alt_domains="$3" + _chk_pre_hook="$4" + _chk_local_addr="$5" _debug _on_before_issue #run pre hook - if [ "$Le_PreHook" ]; then - _info "Run pre hook:'$Le_PreHook'" + if [ "$_chk_pre_hook" ]; then + _info "Run pre hook:'$_chk_pre_hook'" if ! ( - cd "$DOMAIN_PATH" && eval "$Le_PreHook" + cd "$DOMAIN_PATH" && eval "$_chk_pre_hook" ); then _err "Error when run pre hook." return 1 @@ -2729,7 +2731,7 @@ _on_before_issue() { fi fi - _debug Le_LocalAddress "$Le_LocalAddress" + _debug Le_LocalAddress "$_chk_local_addr" alldomains=$(echo "$_chk_main_domain,$_chk_alt_domains" | tr ',' ' ') _index=1 @@ -2761,7 +2763,7 @@ _on_before_issue() { if [ "$_checkport" ]; then _debug _checkport "$_checkport" - _checkaddr="$(_getfield "$Le_LocalAddress" $_addrIndex)" + _checkaddr="$(_getfield "$_chk_local_addr" $_addrIndex)" _debug _checkaddr "$_checkaddr" _addrIndex="$(_math $_addrIndex + 1)" @@ -2792,6 +2794,7 @@ _on_before_issue() { } _on_issue_err() { + _chk_post_hook="$1" _debug _on_issue_err if [ "$LOG_FILE" ]; then _err "Please check log file for more details: $LOG_FILE" @@ -2805,10 +2808,10 @@ _on_issue_err() { fi #run the post hook - if [ "$Le_PostHook" ]; then - _info "Run post hook:'$Le_PostHook'" + if [ "$_chk_post_hook" ]; then + _info "Run post hook:'$_chk_post_hook'" if ! ( - cd "$DOMAIN_PATH" && eval "$Le_PostHook" + cd "$DOMAIN_PATH" && eval "$_chk_post_hook" ); then _err "Error when run post hook." return 1 @@ -2817,12 +2820,14 @@ _on_issue_err() { } _on_issue_success() { + _chk_post_hook="$1" + _chk_renew_hook="$2" _debug _on_issue_success #run the post hook - if [ "$Le_PostHook" ]; then - _info "Run post hook:'$Le_PostHook'" + if [ "$_chk_post_hook" ]; then + _info "Run post hook:'$_chk_post_hook'" if ! ( - cd "$DOMAIN_PATH" && eval "$Le_PostHook" + cd "$DOMAIN_PATH" && eval "$_chk_post_hook" ); then _err "Error when run post hook." return 1 @@ -2830,10 +2835,10 @@ _on_issue_success() { fi #run renew hook - if [ "$IS_RENEW" ] && [ "$Le_RenewHook" ]; then - _info "Run renew hook:'$Le_RenewHook'" + if [ "$IS_RENEW" ] && [ "$_chk_renew_hook" ]; then + _info "Run renew hook:'$_chk_renew_hook'" if ! ( - cd "$DOMAIN_PATH" && eval "$Le_RenewHook" + cd "$DOMAIN_PATH" && eval "$_chk_renew_hook" ); then _err "Error when run renew hook." return 1 @@ -3038,15 +3043,15 @@ issue() { _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") fi _key_length="$4" - Le_RealCertPath="$5" - Le_RealKeyPath="$6" - Le_RealCACertPath="$7" - Le_ReloadCmd="$8" - Le_RealFullChainPath="$9" - Le_PreHook="${10}" - Le_PostHook="${11}" - Le_RenewHook="${12}" - Le_LocalAddress="${13}" + _real_cert="$5" + _real_key="$6" + _real_ca="$7" + _reload_cmd="$8" + _real_fullchain="$9" + _pre_hook="${10}" + _post_hook="${11}" + _renew_hook="${12}" + _local_addr="${13}" #remove these later. if [ "$_web_roots" = "dns-cf" ]; then @@ -3088,12 +3093,12 @@ issue() { _savedomainconf "Le_Alt" "$_alt_domains" _savedomainconf "Le_Webroot" "$_web_roots" - _savedomainconf "Le_PreHook" "$Le_PreHook" - _savedomainconf "Le_PostHook" "$Le_PostHook" - _savedomainconf "Le_RenewHook" "$Le_RenewHook" + _savedomainconf "Le_PreHook" "$_pre_hook" + _savedomainconf "Le_PostHook" "$_post_hook" + _savedomainconf "Le_RenewHook" "$_renew_hook" - if [ "$Le_LocalAddress" ]; then - _savedomainconf "Le_LocalAddress" "$Le_LocalAddress" + if [ "$_local_addr" ]; then + _savedomainconf "Le_LocalAddress" "$_local_addr" else _cleardomainconf "Le_LocalAddress" fi @@ -3109,7 +3114,7 @@ issue() { _key_length="" fi - if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains"; then + if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains" "$_pre_hook" "$_local_addr"; then _err "_on_before_issue." return 1 fi @@ -3119,7 +3124,7 @@ issue() { if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then if ! _regAccount "$_accountkeylength"; then - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi else @@ -3135,7 +3140,7 @@ issue() { if ! createDomainKey "$_main_domain" "$_key_length"; then _err "Create domain key error." _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi fi @@ -3143,7 +3148,7 @@ issue() { if ! _createcsr "$_main_domain" "$_alt_domains" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then _err "Create CSR error." _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi fi @@ -3180,7 +3185,7 @@ issue() { if ! __get_domain_new_authz "$d"; then _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3193,7 +3198,7 @@ issue() { if [ -z "$entry" ]; then _err "Error, can not get domain token $d" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" @@ -3274,7 +3279,7 @@ issue() { if [ "$?" != "0" ]; then _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi dnsadded='1' @@ -3286,7 +3291,7 @@ issue() { _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _err "Please add the TXT records to the domains, and retry again." _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3332,12 +3337,12 @@ issue() { if [ "$vtype" = "$VTYPE_HTTP" ]; then if [ "$_currentRoot" = "$NO_VALUE" ]; then _info "Standalone mode server" - _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")" + _ncaddr="$(_getfield "$_local_addr" "$_ncIndex")" _ncIndex="$(_math $_ncIndex + 1)" _startserver "$keyauthorization" "$_ncaddr" & if [ "$?" != "0" ]; then _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi serverproc="$!" @@ -3353,7 +3358,7 @@ issue() { BACKUP_NGINX_CONF="" if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3388,7 +3393,7 @@ issue() { _err "$d:Can not write token to file : $wellknown_path/$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3427,13 +3432,13 @@ issue() { _SAN_B="$_x.$_y.acme.invalid" _debug2 _SAN_B "$_SAN_B" - _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")" + _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 + _on_issue_err "$_post_hook" return 1 fi fi @@ -3442,7 +3447,7 @@ issue() { _err "$d:Can not get challenge: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3450,7 +3455,7 @@ issue() { _err "$d:Challenge error: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3477,7 +3482,7 @@ issue() { _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi _debug2 original "$response" @@ -3512,7 +3517,7 @@ issue() { fi _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3522,7 +3527,7 @@ issue() { _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3536,7 +3541,7 @@ issue() { if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3578,7 +3583,7 @@ issue() { if [ -z "$Le_LinkCert" ]; then response="$(echo "$response" | _dbase64 "multiline" | _normalizeJson)" _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')" - _on_issue_err + _on_issue_err "$_post_hook" return 1 fi @@ -3640,10 +3645,15 @@ issue() { Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400) _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" - _on_issue_success + _on_issue_success "$_post_hook" "$_renew_hook" - if [ "$Le_RealCertPath$Le_RealKeyPath$Le_RealCACertPath$Le_ReloadCmd$Le_RealFullChainPath" ]; then - _installcert + if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then + _savedomainconf "Le_RealCertPath" "$_real_cert" + _savedomainconf "Le_RealCACertPath" "$_real_ca" + _savedomainconf "Le_RealKeyPath" "$_real_key" + _savedomainconf "Le_ReloadCmd" "$_reload_cmd" + _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" + _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" fi } @@ -3929,104 +3939,107 @@ deploy() { } installcert() { - Le_Domain="$1" - if [ -z "$Le_Domain" ]; then + _main_domain="$1" + if [ -z "$_main_domain" ]; then _usage "Usage: $PROJECT_ENTRY --installcert -d domain.com [--ecc] [--certpath cert-file-path] [--keypath key-file-path] [--capath ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]" return 1 fi - Le_RealCertPath="$2" - Le_RealKeyPath="$3" - Le_RealCACertPath="$4" - Le_ReloadCmd="$5" - Le_RealFullChainPath="$6" + _real_cert="$2" + _real_key="$3" + _real_ca="$4" + _reload_cmd="$5" + _real_fullchain="$6" _isEcc="$7" - _initpath "$Le_Domain" "$_isEcc" + _initpath "$_main_domain" "$_isEcc" if [ ! -d "$DOMAIN_PATH" ]; then - _err "Domain is not valid:'$Le_Domain'" + _err "Domain is not valid:'$_main_domain'" return 1 fi - _installcert + _savedomainconf "Le_RealCertPath" "$_real_cert" + _savedomainconf "Le_RealCACertPath" "$_real_ca" + _savedomainconf "Le_RealKeyPath" "$_real_key" + _savedomainconf "Le_ReloadCmd" "$_reload_cmd" + _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" + + _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" } _installcert() { - _savedomainconf "Le_RealCertPath" "$Le_RealCertPath" - _savedomainconf "Le_RealCACertPath" "$Le_RealCACertPath" - _savedomainconf "Le_RealKeyPath" "$Le_RealKeyPath" - _savedomainconf "Le_ReloadCmd" "$Le_ReloadCmd" - _savedomainconf "Le_RealFullChainPath" "$Le_RealFullChainPath" + _main_domain="$1" + _real_cert="$2" + _real_key="$3" + _real_ca="$4" + _reload_cmd="$5" + _real_fullchain="$6" - if [ "$Le_RealCertPath" = "$NO_VALUE" ]; then - Le_RealCertPath="" + if [ "$_real_cert" = "$NO_VALUE" ]; then + _real_cert="" fi - if [ "$Le_RealKeyPath" = "$NO_VALUE" ]; then - Le_RealKeyPath="" + if [ "$_real_key" = "$NO_VALUE" ]; then + _real_key="" fi - if [ "$Le_RealCACertPath" = "$NO_VALUE" ]; then - Le_RealCACertPath="" + if [ "$_real_ca" = "$NO_VALUE" ]; then + _real_ca="" fi - if [ "$Le_ReloadCmd" = "$NO_VALUE" ]; then - Le_ReloadCmd="" + if [ "$_reload_cmd" = "$NO_VALUE" ]; then + _reload_cmd="" fi - if [ "$Le_RealFullChainPath" = "$NO_VALUE" ]; then - Le_RealFullChainPath="" + if [ "$_real_fullchain" = "$NO_VALUE" ]; then + _real_fullchain="" fi - if [ "$Le_RealCertPath" ]; then - - _info "Installing cert to:$Le_RealCertPath" - if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ]; then + if [ "$_real_cert" ]; then + _info "Installing cert to:$_real_cert" + if [ -f "$_real_cert" ] && [ ! "$IS_RENEW" ]; then mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$Le_RealCertPath" "$DOMAIN_BACKUP_PATH/cert.bak" + cp "$_real_cert" "$DOMAIN_BACKUP_PATH/cert.bak" fi - cat "$CERT_PATH" >"$Le_RealCertPath" + cat "$CERT_PATH" >"$_real_cert" fi - if [ "$Le_RealCACertPath" ]; then - - _info "Installing CA to:$Le_RealCACertPath" - if [ "$Le_RealCACertPath" = "$Le_RealCertPath" ]; then - echo "" >>"$Le_RealCACertPath" - cat "$CA_CERT_PATH" >>"$Le_RealCACertPath" + if [ "$_real_ca" ]; then + _info "Installing CA to:$_real_ca" + if [ "$_real_ca" = "$_real_cert" ]; then + echo "" >>"$_real_ca" + cat "$CA_CERT_PATH" >>"$_real_ca" else - if [ -f "$Le_RealCACertPath" ] && [ ! "$IS_RENEW" ]; then + if [ -f "$_real_ca" ] && [ ! "$IS_RENEW" ]; then mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$Le_RealCACertPath" "$DOMAIN_BACKUP_PATH/ca.bak" + cp "$_real_ca" "$DOMAIN_BACKUP_PATH/ca.bak" fi - cat "$CA_CERT_PATH" >"$Le_RealCACertPath" + cat "$CA_CERT_PATH" >"$_real_ca" fi fi - if [ "$Le_RealKeyPath" ]; then - - _info "Installing key to:$Le_RealKeyPath" - if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ]; then + if [ "$_real_key" ]; then + _info "Installing key to:$_real_key" + if [ -f "$_real_key" ] && [ ! "$IS_RENEW" ]; then mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$Le_RealKeyPath" "$DOMAIN_BACKUP_PATH/key.bak" + cp "$_real_key" "$DOMAIN_BACKUP_PATH/key.bak" fi - cat "$CERT_KEY_PATH" >"$Le_RealKeyPath" + cat "$CERT_KEY_PATH" >"$_real_key" fi - if [ "$Le_RealFullChainPath" ]; then - - _info "Installing full chain to:$Le_RealFullChainPath" - if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ]; then + if [ "$_real_fullchain" ]; then + _info "Installing full chain to:$_real_fullchain" + if [ -f "$_real_fullchain" ] && [ ! "$IS_RENEW" ]; then mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$Le_RealFullChainPath" "$DOMAIN_BACKUP_PATH/fullchain.bak" + cp "$_real_fullchain" "$DOMAIN_BACKUP_PATH/fullchain.bak" fi - cat "$CERT_FULLCHAIN_PATH" >"$Le_RealFullChainPath" + cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" fi - if [ "$Le_ReloadCmd" ]; then - _info "Run Le_ReloadCmd: $Le_ReloadCmd" + if [ "$_reload_cmd" ]; then + _info "Run reload cmd: $_reload_cmd" if ( export CERT_PATH export CERT_KEY_PATH export CA_CERT_PATH export CERT_FULLCHAIN_PATH - cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd" + cd "$DOMAIN_PATH" && eval "$_reload_cmd" ); then _info "$(__green "Reload success")" else From 8796adfd6393257177f96e2b5ab8bf0dfd0d2a47 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 20 Feb 2017 18:03:16 +0800 Subject: [PATCH 184/620] fix https://github.com/Neilpang/acme.sh/issues/614 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index db77c226..1bd955bc 100755 --- a/acme.sh +++ b/acme.sh @@ -1088,7 +1088,7 @@ _readKeyLengthFromCSR() { echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' else _debug "RSA CSR" - echo "$_outcsr" | _egrep_o "^ *Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 + echo "$_outcsr" | _egrep_o "(^ *|^RSA )Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 fi } From 1efb2085e98859261f9b697b1358a4478d5bb5cf Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 20 Feb 2017 20:18:58 +0800 Subject: [PATCH 185/620] fix debug info --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 1bd955bc..43f87e98 100755 --- a/acme.sh +++ b/acme.sh @@ -1730,7 +1730,7 @@ _setopt() { _debug3 APP echo "$__opt$__sep$__val$__end" >>"$__conf" fi - _debug2 "$(grep -n "^$__opt$__sep" "$__conf")" + _debug3 "$(grep -n "^$__opt$__sep" "$__conf")" } #_save_conf file key value From 044da37c953003e284c2307624c858a4fecbba0c Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 21 Feb 2017 21:34:43 +0800 Subject: [PATCH 186/620] change installcert parameter order --- acme.sh | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index 43f87e98..e24d4d9a 100755 --- a/acme.sh +++ b/acme.sh @@ -3653,7 +3653,7 @@ issue() { _savedomainconf "Le_RealKeyPath" "$_real_key" _savedomainconf "Le_ReloadCmd" "$_reload_cmd" _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" - _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" + _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd" fi } @@ -3964,16 +3964,18 @@ installcert() { _savedomainconf "Le_ReloadCmd" "$_reload_cmd" _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" - _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" + _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd" } +#domain cert key ca fullchain reloadcmd backup-prefix _installcert() { _main_domain="$1" _real_cert="$2" _real_key="$3" _real_ca="$4" - _reload_cmd="$5" - _real_fullchain="$6" + _real_fullchain="$5" + _reload_cmd="$6" + _backup_prefix="$7" if [ "$_real_cert" = "$NO_VALUE" ]; then _real_cert="" @@ -3991,11 +3993,13 @@ _installcert() { _real_fullchain="" fi + _backup_path="$DOMAIN_BACKUP_PATH/$_backup_prefix" + mkdir -p "$_backup_path" + if [ "$_real_cert" ]; then _info "Installing cert to:$_real_cert" if [ -f "$_real_cert" ] && [ ! "$IS_RENEW" ]; then - mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$_real_cert" "$DOMAIN_BACKUP_PATH/cert.bak" + cp "$_real_cert" "$_backup_path/cert.bak" fi cat "$CERT_PATH" >"$_real_cert" fi @@ -4007,8 +4011,7 @@ _installcert() { cat "$CA_CERT_PATH" >>"$_real_ca" else if [ -f "$_real_ca" ] && [ ! "$IS_RENEW" ]; then - mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$_real_ca" "$DOMAIN_BACKUP_PATH/ca.bak" + cp "$_real_ca" "$_backup_path/ca.bak" fi cat "$CA_CERT_PATH" >"$_real_ca" fi @@ -4017,8 +4020,7 @@ _installcert() { if [ "$_real_key" ]; then _info "Installing key to:$_real_key" if [ -f "$_real_key" ] && [ ! "$IS_RENEW" ]; then - mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$_real_key" "$DOMAIN_BACKUP_PATH/key.bak" + cp "$_real_key" "$_backup_path/key.bak" fi cat "$CERT_KEY_PATH" >"$_real_key" fi @@ -4026,8 +4028,7 @@ _installcert() { if [ "$_real_fullchain" ]; then _info "Installing full chain to:$_real_fullchain" if [ -f "$_real_fullchain" ] && [ ! "$IS_RENEW" ]; then - mkdir -p "$DOMAIN_BACKUP_PATH" - cp "$_real_fullchain" "$DOMAIN_BACKUP_PATH/fullchain.bak" + cp "$_real_fullchain" "$_backup_path/fullchain.bak" fi cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" fi From 6dfc8fe0ea0f0d0889946d3cc54bd5ec21f7e59d Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 21 Feb 2017 23:18:11 +0800 Subject: [PATCH 187/620] support vsftpd hook --- deploy/README.md | 20 +++++++++++++ deploy/vsftpd.sh | 75 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index fcdf8019..cb500311 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -26,5 +26,25 @@ Before you can deploy your cert, you must [issue the cert first](https://github. (TODO) +## 4. Deploy the cert to local vsftpd server. +```sh +acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd +``` + +The default vsftpd conf file is `/etc/vsftpd.conf`, if your vsftpd conf is not in the default location, you can specify one: + +```sh +export DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf" + +acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd +``` + +The default command to restart vsftpd server is `service vsftpd restart`, if it doesn't work, you can specify one: + +```sh +export DEPLOY_VSFTPD_RELOAD="/etc/init.d/vsftpd restart" + +acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd +``` diff --git a/deploy/vsftpd.sh b/deploy/vsftpd.sh index 5e89ea95..d2d8aa16 100644 --- a/deploy/vsftpd.sh +++ b/deploy/vsftpd.sh @@ -4,6 +4,9 @@ #returns 0 means success, otherwise error. +#DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf" +#DEPLOY_VSFTPD_RELOAD="service vsftpd restart" + ######## Public functions ##################### #domain keyfile certfile cafile fullchain @@ -20,7 +23,75 @@ vsftpd_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - _err "deploy cert to vsftpd server, Not implemented yet" - return 1 + _ssl_path="/etc/acme.sh/vsftpd" + if ! mkdir -p "$_ssl_path"; then + _err "Can not create folder:$_ssl_path" + return 1 + fi + + DEFAULT_VSFTPD_CONF="/etc/vsftpd.conf" + _vsftpd_conf="${DEPLOY_VSFTPD_CONF:-$DEFAULT_VSFTPD_CONF}" + if [ ! -f "$_vsftpd_conf" ]; then + if [ -z "$DEPLOY_VSFTPD_CONF" ]; then + _err "vsftpd conf is not found, please define DEPLOY_VSFTPD_CONF" + return 1 + else + _err "It seems that the specified vsftpd conf is not valid, please check." + return 1 + fi + fi + + if [ ! -w "$_vsftpd_conf" ]; then + _err "The file $_vsftpd_conf is not writable, please change the permission." + return 1 + fi + + _backup_conf="$DOMAIN_BACKUP_PATH/vsftpd.conf.bak" + _info "Backup $_vsftpd_conf to $_backup_conf" + cp "$_vsftpd_conf" "$_backup_conf" + + _info "Copying key and cert" + _real_key="$_ssl_path/vsftpd.key" + if ! cat "$_ckey" >"$_real_key"; then + _err "Error: write key file to: $_real_key" + return 1 + fi + _real_fullchain="$_ssl_path/vsftpd.chain.pem" + if ! cat "$_cfullchain" >"$_real_fullchain"; then + _err "Error: write key file to: $_real_fullchain" + return 1 + fi + _info "Modify vsftpd conf: $_vsftpd_conf" + + DEFAULT_VSFTPD_RELOAD="service vsftpd restart" + _reload="${DEPLOY_VSFTPD_RELOAD:-$DEFAULT_VSFTPD_RELOAD}" + if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" \ + && _setopt "$_vsftpd_conf" "rsa_private_key_file" "=" "$_real_key" \ + && _setopt "$_vsftpd_conf" "ssl_enable" "=" "YES" \ + && eval "$_reload"; then + _info "Deploy success!" + if [ "$DEPLOY_VSFTPD_CONF" ]; then + _savedomainconf DEPLOY_VSFTPD_CONF "$DEPLOY_VSFTPD_CONF" + else + _cleardomainconf DEPLOY_VSFTPD_CONF + fi + if [ "$DEPLOY_VSFTPD_RELOAD" ]; then + _savedomainconf DEPLOY_VSFTPD_RELOAD "$DEPLOY_VSFTPD_RELOAD" + else + _cleardomainconf DEPLOY_VSFTPD_RELOAD + fi + return 0 + else + _err "Config vsftpd server error, please report bug to us." + _info "Restoring vsftpd conf" + if cat "$_backup_conf" >"$_vsftpd_conf"; then + _info "Restore conf success" + eval "$_reload" + else + _err "Opps, error restore vsftpd conf, please report bug to us." + fi + return 1 + fi + return 1 } From 45d6e00ff14a48f4ebd9a4a5a5a06cecad6b41d2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 22 Feb 2017 20:17:36 +0800 Subject: [PATCH 188/620] fix format --- deploy/vsftpd.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deploy/vsftpd.sh b/deploy/vsftpd.sh index d2d8aa16..cc57f990 100644 --- a/deploy/vsftpd.sh +++ b/deploy/vsftpd.sh @@ -39,7 +39,7 @@ vsftpd_deploy() { else _err "It seems that the specified vsftpd conf is not valid, please check." return 1 - fi + fi fi if [ ! -w "$_vsftpd_conf" ]; then @@ -50,7 +50,7 @@ vsftpd_deploy() { _backup_conf="$DOMAIN_BACKUP_PATH/vsftpd.conf.bak" _info "Backup $_vsftpd_conf to $_backup_conf" cp "$_vsftpd_conf" "$_backup_conf" - + _info "Copying key and cert" _real_key="$_ssl_path/vsftpd.key" if ! cat "$_ckey" >"$_real_key"; then @@ -63,7 +63,7 @@ vsftpd_deploy() { return 1 fi _info "Modify vsftpd conf: $_vsftpd_conf" - + DEFAULT_VSFTPD_RELOAD="service vsftpd restart" _reload="${DEPLOY_VSFTPD_RELOAD:-$DEFAULT_VSFTPD_RELOAD}" if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" \ From ddf293bbcda2196ea9e7ec18d97d9f5a9a45d4c5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 22 Feb 2017 20:40:33 +0800 Subject: [PATCH 189/620] reload only for renewal --- deploy/vsftpd.sh | 75 ++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/deploy/vsftpd.sh b/deploy/vsftpd.sh index cc57f990..1c6410a6 100644 --- a/deploy/vsftpd.sh +++ b/deploy/vsftpd.sh @@ -29,28 +29,6 @@ vsftpd_deploy() { return 1 fi - DEFAULT_VSFTPD_CONF="/etc/vsftpd.conf" - _vsftpd_conf="${DEPLOY_VSFTPD_CONF:-$DEFAULT_VSFTPD_CONF}" - - if [ ! -f "$_vsftpd_conf" ]; then - if [ -z "$DEPLOY_VSFTPD_CONF" ]; then - _err "vsftpd conf is not found, please define DEPLOY_VSFTPD_CONF" - return 1 - else - _err "It seems that the specified vsftpd conf is not valid, please check." - return 1 - fi - fi - - if [ ! -w "$_vsftpd_conf" ]; then - _err "The file $_vsftpd_conf is not writable, please change the permission." - return 1 - fi - - _backup_conf="$DOMAIN_BACKUP_PATH/vsftpd.conf.bak" - _info "Backup $_vsftpd_conf to $_backup_conf" - cp "$_vsftpd_conf" "$_backup_conf" - _info "Copying key and cert" _real_key="$_ssl_path/vsftpd.key" if ! cat "$_ckey" >"$_real_key"; then @@ -62,15 +40,51 @@ vsftpd_deploy() { _err "Error: write key file to: $_real_fullchain" return 1 fi - _info "Modify vsftpd conf: $_vsftpd_conf" DEFAULT_VSFTPD_RELOAD="service vsftpd restart" _reload="${DEPLOY_VSFTPD_RELOAD:-$DEFAULT_VSFTPD_RELOAD}" - if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" \ - && _setopt "$_vsftpd_conf" "rsa_private_key_file" "=" "$_real_key" \ - && _setopt "$_vsftpd_conf" "ssl_enable" "=" "YES" \ - && eval "$_reload"; then - _info "Deploy success!" + + if [ -z "$IS_RENEW" ]; then + DEFAULT_VSFTPD_CONF="/etc/vsftpd.conf" + _vsftpd_conf="${DEPLOY_VSFTPD_CONF:-$DEFAULT_VSFTPD_CONF}" + if [ ! -f "$_vsftpd_conf" ]; then + if [ -z "$DEPLOY_VSFTPD_CONF" ]; then + _err "vsftpd conf is not found, please define DEPLOY_VSFTPD_CONF" + return 1 + else + _err "It seems that the specified vsftpd conf is not valid, please check." + return 1 + fi + fi + if [ ! -w "$_vsftpd_conf" ]; then + _err "The file $_vsftpd_conf is not writable, please change the permission." + return 1 + fi + _backup_conf="$DOMAIN_BACKUP_PATH/vsftpd.conf.bak" + _info "Backup $_vsftpd_conf to $_backup_conf" + cp "$_vsftpd_conf" "$_backup_conf" + + _info "Modify vsftpd conf: $_vsftpd_conf" + if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" \ + && _setopt "$_vsftpd_conf" "rsa_private_key_file" "=" "$_real_key" \ + && _setopt "$_vsftpd_conf" "ssl_enable" "=" "YES"; then + _info "Set config success!" + else + _err "Config vsftpd server error, please report bug to us." + _info "Restoring vsftpd conf" + if cat "$_backup_conf" >"$_vsftpd_conf"; then + _info "Restore conf success" + eval "$_reload" + else + _err "Opps, error restore vsftpd conf, please report bug to us." + fi + return 1 + fi + fi + + _info "Run reload: $_reload" + if eval "$_reload"; then + _info "Reload success!" if [ "$DEPLOY_VSFTPD_CONF" ]; then _savedomainconf DEPLOY_VSFTPD_CONF "$DEPLOY_VSFTPD_CONF" else @@ -83,8 +97,7 @@ vsftpd_deploy() { fi return 0 else - _err "Config vsftpd server error, please report bug to us." - _info "Restoring vsftpd conf" + _err "Reload error, restoring" if cat "$_backup_conf" >"$_vsftpd_conf"; then _info "Restore conf success" eval "$_reload" @@ -93,5 +106,5 @@ vsftpd_deploy() { fi return 1 fi - return 1 + return 0 } From 35ca729cb939fb3a2e4798992fc51eb5b1ddda88 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 23 Feb 2017 19:01:48 +0800 Subject: [PATCH 190/620] fix doc --- deploy/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index cb500311..40800401 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -13,7 +13,7 @@ Then you can deploy now: ```sh export DEPLOY_CPANEL_USER=myusername export DEPLOY_CPANEL_PASSWORD=PASSWORD -acme.sh --deploy -d example.com --deploy --deploy-hook cpanel +acme.sh --deploy -d example.com --deploy-hook cpanel ``` ## 2. Deploy ssl cert on kong proxy engine based on api. From a239a9efd508aa45d7299df6bb24e216b113251e Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 23 Feb 2017 19:04:08 +0800 Subject: [PATCH 191/620] fix doc --- deploy/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index 40800401..a4e9136f 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -1,12 +1,14 @@ # Using deploy api +Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). + Here are the scripts to deploy the certs/key to the server/services. ## 1. Deploy the certs to your cpanel host. (cpanel deploy hook is not finished yet, this is just an example.) -Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert). + Then you can deploy now: From 1965035166a6259641d3f0c43de930ebb8d8b878 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 23 Feb 2017 20:03:03 +0800 Subject: [PATCH 192/620] support exim4 deploy --- deploy/README.md | 22 ++++++++++++ deploy/exim4.sh | 92 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 112 insertions(+), 2 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index a4e9136f..4a13e096 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -50,3 +50,25 @@ 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 +``` + diff --git a/deploy/exim4.sh b/deploy/exim4.sh index b53f58ec..bf92b438 100644 --- a/deploy/exim4.sh +++ b/deploy/exim4.sh @@ -4,6 +4,9 @@ #returns 0 means success, otherwise error. +#DEPLOY_EXIM4_CONF="/etc/exim/exim.conf" +#DEPLOY_EXIM4_RELOAD="service exim4 restart" + ######## Public functions ##################### #domain keyfile certfile cafile fullchain @@ -20,7 +23,92 @@ exim4_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - _err "deploy cert to exim4 server, Not implemented yet" - return 1 + _ssl_path="/etc/acme.sh/exim4" + if ! mkdir -p "$_ssl_path"; then + _err "Can not create folder:$_ssl_path" + return 1 + fi + + _info "Copying key and cert" + _real_key="$_ssl_path/exim4.key" + if ! cat "$_ckey" >"$_real_key"; then + _err "Error: write key file to: $_real_key" + return 1 + fi + _real_fullchain="$_ssl_path/exim4.pem" + if ! cat "$_cfullchain" >"$_real_fullchain"; then + _err "Error: write key file to: $_real_fullchain" + return 1 + fi + + DEFAULT_EXIM4_RELOAD="service exim4 restart" + _reload="${DEPLOY_EXIM4_RELOAD:-$DEFAULT_EXIM4_RELOAD}" + + if [ -z "$IS_RENEW" ]; then + DEFAULT_EXIM4_CONF="/etc/exim/exim.conf" + if [ ! -f "$DEFAULT_EXIM4_CONF" ]; then + DEFAULT_EXIM4_CONF="/etc/exim4/exim4.conf.template" + fi + _exim4_conf="${DEPLOY_EXIM4_CONF:-$DEFAULT_EXIM4_CONF}" + _debug _exim4_conf "$_exim4_conf" + if [ ! -f "$_exim4_conf" ]; then + if [ -z "$DEPLOY_EXIM4_CONF" ]; then + _err "exim4 conf is not found, please define DEPLOY_EXIM4_CONF" + return 1 + else + _err "It seems that the specified exim4 conf is not valid, please check." + return 1 + fi + fi + if [ ! -w "$_exim4_conf" ]; then + _err "The file $_exim4_conf is not writable, please change the permission." + return 1 + fi + _backup_conf="$DOMAIN_BACKUP_PATH/exim4.conf.bak" + _info "Backup $_exim4_conf to $_backup_conf" + cp "$_exim4_conf" "$_backup_conf" + + _info "Modify exim4 conf: $_exim4_conf" + if _setopt "$_exim4_conf" "tls_certificate" "=" "$_real_fullchain" \ + && _setopt "$_exim4_conf" "tls_privatekey" "=" "$_real_key"; then + _info "Set config success!" + else + _err "Config exim4 server error, please report bug to us." + _info "Restoring exim4 conf" + if cat "$_backup_conf" >"$_exim4_conf"; then + _info "Restore conf success" + eval "$_reload" + else + _err "Opps, error restore exim4 conf, please report bug to us." + fi + return 1 + fi + fi + + _info "Run reload: $_reload" + if eval "$_reload"; then + _info "Reload success!" + if [ "$DEPLOY_EXIM4_CONF" ]; then + _savedomainconf DEPLOY_EXIM4_CONF "$DEPLOY_EXIM4_CONF" + else + _cleardomainconf DEPLOY_EXIM4_CONF + fi + if [ "$DEPLOY_EXIM4_RELOAD" ]; then + _savedomainconf DEPLOY_EXIM4_RELOAD "$DEPLOY_EXIM4_RELOAD" + else + _cleardomainconf DEPLOY_EXIM4_RELOAD + fi + return 0 + else + _err "Reload error, restoring" + if cat "$_backup_conf" >"$_exim4_conf"; then + _info "Restore conf success" + eval "$_reload" + else + _err "Opps, error restore exim4 conf, please report bug to us." + fi + return 1 + fi + return 0 } From 7b2fa1edb41a3b8a447cc590d0450a4a60c4029f Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Fri, 2 Dec 2016 20:10:13 +0000 Subject: [PATCH 193/620] add API for www.do.de/www.resellerinterface.de --- dnsapi/dns_do.sh | 167 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100755 dnsapi/dns_do.sh diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh new file mode 100755 index 00000000..43ce678f --- /dev/null +++ b/dnsapi/dns_do.sh @@ -0,0 +1,167 @@ +#!/usr/bin/env sh + +# DNS API for Domain-Offensive / Resellerinterface / Domainrobot + +# DO_PID="KD-1234567" +# DO_PW="cdfkjl3n2" + +DO_URL="https://soap.resellerinterface.de/" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_do_add() { + fulldomain=$1 + txtvalue=$2 + _cookiejar="$(_mktemp)" + if _dns_do_authenticate; then + _info "Adding TXT record to ${_domain} as ${fulldomain}" + _dns_do_soap createRR origin "${_domain}" name "${fulldomain}" type TXT data "${txtvalue}" ttl 300 + if _contains "${response}" '>success<'; then + return 0 + fi + _err "Could not create resource record, check logs" + fi + return 1 +} + +#fulldomain +dns_do_rm() { + fulldomain=$1 + _cookiejar="$(_mktemp)" + if _dns_do_authenticate; then + if _dns_do_list_rrs; then + for _rrid in ${_rr_list}; do + _info "Deleting resource record $_rrid for $_domain" + _dns_do_soap deleteRR origin "${_domain}" rrid "${_rrid}" + if ! _contains "${response}" '>success<'; then + _err "Could not delete resource record for ${_domain}, id ${_rrid}" + fi + done + return 0 + fi + fi + return 1 +} + +#################### Private functions below ################################## +_dns_do_authenticate() { + _info "Authenticating as ${DO_PID}" + _dns_do_soap authPartner partner "${DO_PID}" password "${DO_PW}" + if _contains "${response}" '>success<'; then + _get_root "$fulldomain" + _debug "_domain $_domain" + return 0 + else + _err "Authentication failed, check logs" + fi + return 1 +} + +_dns_do_list_rrs() { + _dns_do_soap getRRList origin "${_domain}" + if ! _contains "${response}" 'SOAP-ENC:Array'; then + _err "getRRList origin ${_domain} failed" + return 1 + fi + _rr_list="$(echo "${response}" \ + | tr -d "\n\r\t" \ + | sed -e 's//\n/g' \ + | grep -F ">${fulldomain}" \ + | sed -e 's//\n\0/g' \ + | grep -F '>id' \ + | sed -re 's/.*]*>([^<]+)<\/value>.*/\1/')" + [ "${_rr_list}" ] +} + +_dns_do_soap() { + func="$1" + shift + # put the parameters to xml + body="" + while [ "$1" ] ; do + _k="$1" + shift + _v="$1" + shift + body="$body<$_k>$_v" + done + body="$body" + _debug2 "SOAP request ${body}" + + # build SOAP XML + _xml=' + + '"$body"' +' + + # set SOAP headers + _H1="SOAPAction: ${DO_URL}#${func}" + # add cookie header if present + [ -s "${_cookiejar}" ] && _H2="$(cat "${_cookiejar}")" + + if ! response="$(_post "${_xml}" "${DO_URL}")"; then + _err "Error <$1>" + return 1 + fi + _debug2 "SOAP response $response" + + # retrieve cookie header + grep -F 'Set-Cookie:' "$HTTP_HEADER" | sed -re 's/^Set-(Cookie: [^;]+).*/\1/' | head -1 > "${_cookiejar}" + + return 0 +} + +_get_root() { + domain=$1 + i=1 + + _all_domains="$(_mktemp)" + _dns_do_soap getDomainList + echo "${response}" | tr -d "\n\r\t " | grep -Eo 'domain]+>[^<]+' | sed -re 's/^domain<\/key>]+>//g' > "${_all_domains}" + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + return 1 + fi + + if grep -qF "$h" "${_all_domains}"; then + _domain="$h" + return 0 + fi + + i=$(_math $i + 1) + done + _debug "$domain not found" + + return 1 +} + +_info() { + if [ -z "$2" ]; then + echo "[$(date)] $1" + else + echo "[$(date)] $1='$2'" + fi +} + +_err() { + _info "$@" >&2 + return 1 +} + +_debug() { + if [ -z "$DEBUG" ]; then + return + fi + _err "$@" + return 0 +} + +_debug2() { + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + _debug "$@" + fi + return +} From 76a3371b402b3006ee2f26872debffc8b6dca103 Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Sat, 3 Dec 2016 10:07:13 +0000 Subject: [PATCH 194/620] remove non-POSIX sed -r and use built-in functions --- dnsapi/dns_do.sh | 43 ++++++++----------------------------------- 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 43ce678f..cea1beb3 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -67,10 +67,11 @@ _dns_do_list_rrs() { _rr_list="$(echo "${response}" \ | tr -d "\n\r\t" \ | sed -e 's//\n/g' \ - | grep -F ">${fulldomain}" \ - | sed -e 's//\n\0/g' \ - | grep -F '>id' \ - | sed -re 's/.*]*>([^<]+)<\/value>.*/\1/')" + | fgrep ">${fulldomain}" \ + | sed -e 's/<\/item>/\n/g' \ + | grep '>id[0-9]{1,16}<' \ + | tr -d '><')" [ "${_rr_list}" ] } @@ -107,7 +108,7 @@ _dns_do_soap() { _debug2 "SOAP response $response" # retrieve cookie header - grep -F 'Set-Cookie:' "$HTTP_HEADER" | sed -re 's/^Set-(Cookie: [^;]+).*/\1/' | head -1 > "${_cookiejar}" + cat "$HTTP_HEADER" | _egrep_o 'Cookie: [^;]+' | head -1 > "${_cookiejar}" return 0 } @@ -118,7 +119,7 @@ _get_root() { _all_domains="$(_mktemp)" _dns_do_soap getDomainList - echo "${response}" | tr -d "\n\r\t " | grep -Eo 'domain]+>[^<]+' | sed -re 's/^domain<\/key>]+>//g' > "${_all_domains}" + echo "${response}" | tr -d "\n\r\t " | _egrep_o 'domain]+>[^<]+' | sed -e 's/^domain<\/key>]+>//g' > "${_all_domains}" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) @@ -126,7 +127,7 @@ _get_root() { return 1 fi - if grep -qF "$h" "${_all_domains}"; then + if fgrep -q "$h" "${_all_domains}"; then _domain="$h" return 0 fi @@ -137,31 +138,3 @@ _get_root() { return 1 } - -_info() { - if [ -z "$2" ]; then - echo "[$(date)] $1" - else - echo "[$(date)] $1='$2'" - fi -} - -_err() { - _info "$@" >&2 - return 1 -} - -_debug() { - if [ -z "$DEBUG" ]; then - return - fi - _err "$@" - return 0 -} - -_debug2() { - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - _debug "$@" - fi - return -} From 88ed5e506a9c1f862fc99d4c681bf47b2b97f253 Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Sat, 3 Dec 2016 19:04:31 +0000 Subject: [PATCH 195/620] fix whitespace and UUOC --- dnsapi/dns_do.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index cea1beb3..034e6aa6 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -80,7 +80,7 @@ _dns_do_soap() { shift # put the parameters to xml body="" - while [ "$1" ] ; do + while [ "$1" ]; do _k="$1" shift _v="$1" @@ -108,7 +108,7 @@ _dns_do_soap() { _debug2 "SOAP response $response" # retrieve cookie header - cat "$HTTP_HEADER" | _egrep_o 'Cookie: [^;]+' | head -1 > "${_cookiejar}" + _egrep_o 'Cookie: [^;]+' < "$HTTP_HEADER" | head -1 >"${_cookiejar}" return 0 } @@ -119,7 +119,7 @@ _get_root() { _all_domains="$(_mktemp)" _dns_do_soap getDomainList - echo "${response}" | tr -d "\n\r\t " | _egrep_o 'domain]+>[^<]+' | sed -e 's/^domain<\/key>]+>//g' > "${_all_domains}" + echo "${response}" | tr -d "\n\r\t " | _egrep_o 'domain]+>[^<]+' | sed -e 's/^domain<\/key>]+>//g' >"${_all_domains}" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) From 0d4035e99662c737ab4160e6a77e8071f620c4c4 Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Sat, 3 Dec 2016 19:24:42 +0000 Subject: [PATCH 196/620] remove fgrep, escape regex chars instead --- dnsapi/dns_do.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 034e6aa6..075cb3b0 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -67,7 +67,7 @@ _dns_do_list_rrs() { _rr_list="$(echo "${response}" \ | tr -d "\n\r\t" \ | sed -e 's//\n/g' \ - | fgrep ">${fulldomain}" \ + | grep ">$(_regexcape "$fulldomain")" \ | sed -e 's/<\/item>/\n/g' \ | grep '>id[0-9]{1,16}<' \ @@ -127,7 +127,7 @@ _get_root() { return 1 fi - if fgrep -q "$h" "${_all_domains}"; then + if grep -q "$(_regexcape "$h")" "${_all_domains}"; then _domain="$h" return 0 fi @@ -138,3 +138,7 @@ _get_root() { return 1 } + +_regexcape() { + echo "$1" | sed -e 's/\([]\.$*^[]\)/\\\1/g' +} From 3ebbeb103c195737b5d234a60c73056a9a5bb88f Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Sat, 3 Dec 2016 19:27:46 +0000 Subject: [PATCH 197/620] old habits --- dnsapi/dns_do.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 075cb3b0..cc8f339e 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -108,7 +108,7 @@ _dns_do_soap() { _debug2 "SOAP response $response" # retrieve cookie header - _egrep_o 'Cookie: [^;]+' < "$HTTP_HEADER" | head -1 >"${_cookiejar}" + _egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | head -1 >"${_cookiejar}" return 0 } From b95a99e0c2c8aa0e31b44df39fbe46119864dd55 Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Mon, 5 Dec 2016 20:35:31 +0000 Subject: [PATCH 198/620] remove cookiejar temp file --- dnsapi/dns_do.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index cc8f339e..17ab23d7 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -98,8 +98,6 @@ _dns_do_soap() { # set SOAP headers _H1="SOAPAction: ${DO_URL}#${func}" - # add cookie header if present - [ -s "${_cookiejar}" ] && _H2="$(cat "${_cookiejar}")" if ! response="$(_post "${_xml}" "${DO_URL}")"; then _err "Error <$1>" @@ -108,7 +106,7 @@ _dns_do_soap() { _debug2 "SOAP response $response" # retrieve cookie header - _egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | head -1 >"${_cookiejar}" + _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | head -1)" return 0 } From 743f821f1ee9e4827e95a4b1c4088949cbfc78ac Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Mon, 5 Dec 2016 20:49:46 +0000 Subject: [PATCH 199/620] improve error message on failed authentication --- dnsapi/dns_do.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 17ab23d7..7576092b 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -53,7 +53,7 @@ _dns_do_authenticate() { _debug "_domain $_domain" return 0 else - _err "Authentication failed, check logs" + _err "Authentication failed, are DO_PID and DO_PW set correctly?" fi return 1 } From d1d2f6f4518cc7332b92ef856471b1a76a6c03e8 Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Mon, 5 Dec 2016 20:56:38 +0000 Subject: [PATCH 200/620] avoid temp file for domain list --- dnsapi/dns_do.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 7576092b..1a9458f8 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -115,9 +115,11 @@ _get_root() { domain=$1 i=1 - _all_domains="$(_mktemp)" _dns_do_soap getDomainList - echo "${response}" | tr -d "\n\r\t " | _egrep_o 'domain]+>[^<]+' | sed -e 's/^domain<\/key>]+>//g' >"${_all_domains}" + _all_domains="/$(echo "${response}" \ + | tr -d "\n\r\t " \ + | _egrep_o 'domain]+>[^<]+' \ + | sed -e 's/^domain<\/key>]*>//g')" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) @@ -125,7 +127,7 @@ _get_root() { return 1 fi - if grep -q "$(_regexcape "$h")" "${_all_domains}"; then + if _contains "${_all_domains}" "^$(_regexcape "$h")\$"; then _domain="$h" return 0 fi From 1cb6e9e7d0653b2920fb6eac0bc11d3abdfa5190 Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Wed, 7 Dec 2016 11:36:22 +0100 Subject: [PATCH 201/620] remove cookiejar file d'oh --- dnsapi/dns_do.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 1a9458f8..edcf4559 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -13,7 +13,6 @@ DO_URL="https://soap.resellerinterface.de/" dns_do_add() { fulldomain=$1 txtvalue=$2 - _cookiejar="$(_mktemp)" if _dns_do_authenticate; then _info "Adding TXT record to ${_domain} as ${fulldomain}" _dns_do_soap createRR origin "${_domain}" name "${fulldomain}" type TXT data "${txtvalue}" ttl 300 From cdec38ba12a3779f257f321fd8a84b02fee0dbec Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Wed, 7 Dec 2016 11:39:10 +0100 Subject: [PATCH 202/620] return error if any removal failed --- dnsapi/dns_do.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index edcf4559..1450ee5a 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -30,14 +30,16 @@ dns_do_rm() { _cookiejar="$(_mktemp)" if _dns_do_authenticate; then if _dns_do_list_rrs; then + _dns_do_had_error=0 for _rrid in ${_rr_list}; do _info "Deleting resource record $_rrid for $_domain" _dns_do_soap deleteRR origin "${_domain}" rrid "${_rrid}" if ! _contains "${response}" '>success<'; then + _dns_do_had_error=1 _err "Could not delete resource record for ${_domain}, id ${_rrid}" fi done - return 0 + return _dns_do_had_error fi fi return 1 From e55605dbe9b91702f9b93ac0c0a84736fb8e0145 Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Wed, 7 Dec 2016 11:41:32 +0100 Subject: [PATCH 203/620] remove _all_ mktemp --- dnsapi/dns_do.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 1450ee5a..43a73b97 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -27,7 +27,6 @@ dns_do_add() { #fulldomain dns_do_rm() { fulldomain=$1 - _cookiejar="$(_mktemp)" if _dns_do_authenticate; then if _dns_do_list_rrs; then _dns_do_had_error=0 From 1633d14547ad6d1e5521af0ce814373cd840fc14 Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Wed, 7 Dec 2016 12:07:40 +0100 Subject: [PATCH 204/620] forgot dollar sign --- dnsapi/dns_do.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 43a73b97..bbf86bac 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -38,7 +38,7 @@ dns_do_rm() { _err "Could not delete resource record for ${_domain}, id ${_rrid}" fi done - return _dns_do_had_error + return $_dns_do_had_error fi fi return 1 From bf8ffade29daca74e15e53cf40cf1b1ba451272f Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Thu, 8 Dec 2016 08:43:29 +0100 Subject: [PATCH 205/620] replace head -1, add link to GitHub --- dnsapi/dns_do.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index bbf86bac..b718cd41 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -2,6 +2,9 @@ # DNS API for Domain-Offensive / Resellerinterface / Domainrobot +# Report bugs at https://github.com/seidler2547/acme.sh/issues + +# set these environment variables to match your customer ID and password: # DO_PID="KD-1234567" # DO_PW="cdfkjl3n2" @@ -106,7 +109,7 @@ _dns_do_soap() { _debug2 "SOAP response $response" # retrieve cookie header - _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | head -1)" + _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)" return 0 } From 383fa8401d1dffb6d9a325b8df1c3324aba8f3b8 Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Thu, 19 Jan 2017 09:35:47 +0100 Subject: [PATCH 206/620] Remove stray characater fixes issue where the first listed domain would not work --- dnsapi/dns_do.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index b718cd41..b08e6f1e 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -119,7 +119,7 @@ _get_root() { i=1 _dns_do_soap getDomainList - _all_domains="/$(echo "${response}" \ + _all_domains="$(echo "${response}" \ | tr -d "\n\r\t " \ | _egrep_o 'domain]+>[^<]+' \ | sed -e 's/^domain<\/key>]*>//g')" From 9efd40a3662d64c54eeb98858ddbd9bfc589ba2c Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Sun, 19 Feb 2017 21:26:25 +0000 Subject: [PATCH 207/620] use export for headers --- dnsapi/dns_do.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index b08e6f1e..06a86b28 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -100,7 +100,7 @@ _dns_do_soap() { ' # set SOAP headers - _H1="SOAPAction: ${DO_URL}#${func}" + export _H1="SOAPAction: ${DO_URL}#${func}" if ! response="$(_post "${_xml}" "${DO_URL}")"; then _err "Error <$1>" @@ -109,7 +109,7 @@ _dns_do_soap() { _debug2 "SOAP response $response" # retrieve cookie header - _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)" + export _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)" return 0 } From 3d6a125bdc08e4419697a1913d00d68e0715b5e8 Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Sun, 19 Feb 2017 21:34:10 +0000 Subject: [PATCH 208/620] add documentation --- README.md | 1 + dnsapi/README.md | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/README.md b/README.md index b33f8636..c8aeeb0f 100644 --- a/README.md +++ b/README.md @@ -293,6 +293,7 @@ You don't have to do anything manually! 1. Linode.com API 1. FreeDNS (https://freedns.afraid.org/) 1. cyon.ch +1. Domain-Offensive/Resellerinterface/Domainrobot API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index fd88d579..3be5a7fe 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -240,6 +240,7 @@ acme.sh --issue --dns dns_ispconfig -d example.com -d www.example.com The `ISPC_User`, `ISPC_Password`, `ISPC_Api`and `ISPC_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +<<<<<<< HEAD ## 13. Use Alwaysdata domain API First you need to login to your Alwaysdata account to get your API Key. @@ -323,6 +324,19 @@ acme.sh --issue --dns dns_cyon -d example.com -d www.example.com The `CY_Username`, `CY_Password` and `CY_OTP_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 17. Use Domain-Offensive/Resellerinterface/Domainrobot API + +You will need your login credentials (Partner ID+Password) to the Resellerinterface, and export them before you run `acme.sh`: +``` +export DO_PID="KD-1234567" +export DO_PW="cdfkjl3n2" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_do -d example.com -d www.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. From 2b2b65fe1877725f4c7d400da28847bb31a09fbc Mon Sep 17 00:00:00 2001 From: seidler2547 Date: Sun, 19 Feb 2017 21:42:55 +0000 Subject: [PATCH 209/620] Declare and assign separately to avoid masking return values --- dnsapi/dns_do.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 06a86b28..3a2f8f49 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -109,7 +109,8 @@ _dns_do_soap() { _debug2 "SOAP response $response" # retrieve cookie header - export _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)" + _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)" + export _H2 return 0 } From abf4278d0911be6ff199380c66542b93ecca9824 Mon Sep 17 00:00:00 2001 From: Stefan Seidel Date: Sun, 19 Feb 2017 21:46:33 +0000 Subject: [PATCH 210/620] resolve conflicts --- dnsapi/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 3be5a7fe..7df7142a 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -240,7 +240,6 @@ acme.sh --issue --dns dns_ispconfig -d example.com -d www.example.com The `ISPC_User`, `ISPC_Password`, `ISPC_Api`and `ISPC_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. -<<<<<<< HEAD ## 13. Use Alwaysdata domain API First you need to login to your Alwaysdata account to get your API Key. From e6cd596dc90bf51e3237b420b1715b000b64c3a6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 25 Feb 2017 18:02:23 +0800 Subject: [PATCH 211/620] add debug info --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e24d4d9a..b989d246 100755 --- a/acme.sh +++ b/acme.sh @@ -4369,7 +4369,7 @@ _precheck() { fi if ! _exists "$OPENSSL_BIN"; then - _err "Please install openssl first." + _err "Please install openssl first. OPENSSL_BIN=$OPENSSL_BIN" _err "We need openssl to generate keys." return 1 fi From 851fedf7512216c1926f3f64e899167ed6f06f56 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 25 Feb 2017 19:08:00 +0800 Subject: [PATCH 212/620] rename OPENSSL_BIN to ACME_OPENSSL_BIN --- acme.sh | 80 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/acme.sh b/acme.sh index b989d246..937da149 100755 --- a/acme.sh +++ b/acme.sh @@ -137,11 +137,11 @@ _printargs() { _dlg_versions() { echo "Diagnosis versions: " - echo "openssl:$OPENSSL_BIN" - if _exists "$OPENSSL_BIN"; then - $OPENSSL_BIN version 2>&1 + echo "openssl:$ACME_OPENSSL_BIN" + if _exists "$ACME_OPENSSL_BIN"; then + $ACME_OPENSSL_BIN version 2>&1 else - echo "$OPENSSL_BIN doesn't exists." + echo "$ACME_OPENSSL_BIN doesn't exists." fi echo "apache:" @@ -780,19 +780,19 @@ _base64() { [ "" ] #urgly if [ "$1" ]; then _debug3 "base64 multiline:'$1'" - $OPENSSL_BIN base64 -e + $ACME_OPENSSL_BIN base64 -e else _debug3 "base64 single line." - $OPENSSL_BIN base64 -e | tr -d '\r\n' + $ACME_OPENSSL_BIN base64 -e | tr -d '\r\n' fi } #Usage: multiline _dbase64() { if [ "$1" ]; then - $OPENSSL_BIN base64 -d -A + $ACME_OPENSSL_BIN base64 -d -A else - $OPENSSL_BIN base64 -d + $ACME_OPENSSL_BIN base64 -d fi } @@ -809,9 +809,9 @@ _digest() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then if [ "$outputhex" ]; then - $OPENSSL_BIN dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' + $ACME_OPENSSL_BIN dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' else - $OPENSSL_BIN dgst -"$alg" -binary | _base64 + $ACME_OPENSSL_BIN dgst -"$alg" -binary | _base64 fi else _err "$alg is not supported yet" @@ -834,9 +834,9 @@ _hmac() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then if [ "$outputhex" ]; then - ($OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || $OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' ' + ($ACME_OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || $ACME_OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' ' else - $OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || $OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary + $ACME_OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || $ACME_OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary fi else _err "$alg is not supported yet" @@ -855,7 +855,7 @@ _sign() { return 1 fi - _sign_openssl="$OPENSSL_BIN dgst -sign $keyfile " + _sign_openssl="$ACME_OPENSSL_BIN dgst -sign $keyfile " if [ "$alg" = "sha256" ]; then _sign_openssl="$_sign_openssl -$alg" else @@ -866,7 +866,7 @@ _sign() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then $_sign_openssl | _base64 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then - if ! _signedECText="$($_sign_openssl | $OPENSSL_BIN asn1parse -inform DER)"; then + if ! _signedECText="$($_sign_openssl | $ACME_OPENSSL_BIN asn1parse -inform DER)"; then _err "Sign failed: $_sign_openssl" _err "Key file: $keyfile" _err "Key content:$(wc -l <"$keyfile") lises" @@ -929,10 +929,10 @@ _createkey() { if _isEccKey "$length"; then _debug "Using ec name: $eccname" - $OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f" + $ACME_OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f" else _debug "Using RSA: $length" - $OPENSSL_BIN genrsa "$length" 2>/dev/null >"$f" + $ACME_OPENSSL_BIN genrsa "$length" 2>/dev/null >"$f" fi if [ "$?" != "0" ]; then @@ -1019,9 +1019,9 @@ _createcsr() { _csr_cn="$(_idn "$domain")" _debug2 _csr_cn "$_csr_cn" if _contains "$(uname -a)" "MINGW"; then - $OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" + $ACME_OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" else - $OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" + $ACME_OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" fi } @@ -1033,7 +1033,7 @@ _signcsr() { cert="$4" _debug "_signcsr" - _msg="$($OPENSSL_BIN x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" + _msg="$($ACME_OPENSSL_BIN x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" _ret="$?" _debug "$_msg" return $_ret @@ -1046,7 +1046,7 @@ _readSubjectFromCSR() { _usage "_readSubjectFromCSR mycsr.csr" return 1 fi - $OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' + $ACME_OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' } #_csrfile @@ -1061,7 +1061,7 @@ _readSubjectAltNamesFromCSR() { _csrsubj="$(_readSubjectFromCSR "$_csrfile")" _debug _csrsubj "$_csrsubj" - _dnsAltnames="$($OPENSSL_BIN req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" + _dnsAltnames="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" _debug _dnsAltnames "$_dnsAltnames" if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then @@ -1082,7 +1082,7 @@ _readKeyLengthFromCSR() { return 1 fi - _outcsr="$($OPENSSL_BIN req -noout -text -in "$_csrfile")" + _outcsr="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile")" if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then _debug "ECC CSR" echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' @@ -1136,9 +1136,9 @@ toPkcs() { _initpath "$domain" "$_isEcc" if [ "$pfxPassword" ]; then - $OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" + $ACME_OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" else - $OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" + $ACME_OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" fi if [ "$?" = "0" ]; then @@ -1300,7 +1300,7 @@ _calcjwk() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "RSA key" - pub_exp=$($OPENSSL_BIN rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) + pub_exp=$($ACME_OPENSSL_BIN rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) if [ "${#pub_exp}" = "5" ]; then pub_exp=0$pub_exp fi @@ -1309,7 +1309,7 @@ _calcjwk() { e=$(echo "$pub_exp" | _h2b | _base64) _debug3 e "$e" - modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) + modulus=$($ACME_OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)" _debug3 n "$n" @@ -1322,12 +1322,12 @@ _calcjwk() { JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "EC key" - crv="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" + crv="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv "$crv" if [ -z "$crv" ]; then _debug "Let's try ASN1 OID" - crv_oid="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" + crv_oid="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv_oid "$crv_oid" case "${crv_oid}" in "prime256v1") @@ -1347,15 +1347,15 @@ _calcjwk() { _debug3 crv "$crv" fi - pubi="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" + pubi="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" pubi=$(_math "$pubi" + 1) _debug3 pubi "$pubi" - pubj="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" + pubj="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" pubj=$(_math "$pubj" - 1) _debug3 pubj "$pubj" - pubtext="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" + pubtext="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" _debug3 pubtext "$pubtext" xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" @@ -1964,7 +1964,7 @@ _starttlsserver() { return 1 fi - __S_OPENSSL="$OPENSSL_BIN s_server -cert $TLS_CERT -key $TLS_KEY " + __S_OPENSSL="$ACME_OPENSSL_BIN s_server -cert $TLS_CERT -key $TLS_KEY " if [ "$opaddr" ]; then __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" else @@ -2143,8 +2143,8 @@ _initpath() { CERT_HOME="$_DEFAULT_CERT_HOME" fi - if [ -z "$OPENSSL_BIN" ]; then - OPENSSL_BIN="$DEFAULT_OPENSSL_BIN" + if [ -z "$ACME_OPENSSL_BIN" ] || [ ! -f "$ACME_OPENSSL_BIN" ] || [ ! -x "$ACME_OPENSSL_BIN" ] ; then + ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN" fi if [ -z "$1" ]; then @@ -4368,8 +4368,8 @@ _precheck() { fi fi - if ! _exists "$OPENSSL_BIN"; then - _err "Please install openssl first. OPENSSL_BIN=$OPENSSL_BIN" + if ! _exists "$ACME_OPENSSL_BIN"; then + _err "Please install openssl first. ACME_OPENSSL_BIN=$ACME_OPENSSL_BIN" _err "We need openssl to generate keys." return 1 fi @@ -4791,9 +4791,9 @@ _processAccountConf() { fi if [ "$_openssl_bin" ]; then - _saveaccountconf "OPENSSL_BIN" "$_openssl_bin" - elif [ "$OPENSSL_BIN" ] && [ "$OPENSSL_BIN" != "$DEFAULT_OPENSSL_BIN" ]; then - _saveaccountconf "OPENSSL_BIN" "$OPENSSL_BIN" + _saveaccountconf "ACME_OPENSSL_BIN" "$_openssl_bin" + elif [ "$ACME_OPENSSL_BIN" ] && [ "$ACME_OPENSSL_BIN" != "$DEFAULT_OPENSSL_BIN" ]; then + _saveaccountconf "ACME_OPENSSL_BIN" "$ACME_OPENSSL_BIN" fi if [ "$_auto_upgrade" ]; then @@ -5219,7 +5219,7 @@ _process() { ;; --openssl-bin) _openssl_bin="$2" - OPENSSL_BIN="$_openssl_bin" + ACME_OPENSSL_BIN="$_openssl_bin" ;; *) _err "Unknown parameter : $1" From 77f1ea40cd02024568b36daebdce55b2f41f565d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 25 Feb 2017 19:12:20 +0800 Subject: [PATCH 213/620] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 937da149..d9f5a34e 100755 --- a/acme.sh +++ b/acme.sh @@ -2143,7 +2143,7 @@ _initpath() { CERT_HOME="$_DEFAULT_CERT_HOME" fi - if [ -z "$ACME_OPENSSL_BIN" ] || [ ! -f "$ACME_OPENSSL_BIN" ] || [ ! -x "$ACME_OPENSSL_BIN" ] ; then + if [ -z "$ACME_OPENSSL_BIN" ] || [ ! -f "$ACME_OPENSSL_BIN" ] || [ ! -x "$ACME_OPENSSL_BIN" ]; then ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN" fi From 4410226db1bf51e543ea46d84cdb9d567a93d92a Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 25 Feb 2017 19:31:52 +0800 Subject: [PATCH 214/620] add --toPkcs8 command fix https://github.com/Neilpang/acme.sh/issues/664 --- acme.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/acme.sh b/acme.sh index d9f5a34e..e55265d0 100755 --- a/acme.sh +++ b/acme.sh @@ -1147,6 +1147,27 @@ toPkcs() { } +#domain [isEcc] +toPkcs8() { + domain="$1" + + if [ -z "$domain" ]; then + _usage "Usage: $PROJECT_ENTRY --toPkcs8 -d domain [--ecc]" + return 1 + fi + + _isEcc="$2" + + _initpath "$domain" "$_isEcc" + + $ACME_OPENSSL_BIN pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in "$CERT_KEY_PATH" -out "$CERT_PKCS8_PATH" + + if [ "$?" = "0" ]; then + _info "Success, $CERT_PKCS8_PATH" + fi + +} + #[2048] createAccountKey() { _info "Creating account key" @@ -2200,6 +2221,9 @@ _initpath() { if [ -z "$CERT_PFX_PATH" ]; then CERT_PFX_PATH="$DOMAIN_PATH/$domain.pfx" fi + if [ -z "$CERT_PKCS8_PATH" ]; then + CERT_PKCS8_PATH="$DOMAIN_PATH/$domain.pkcs8" + fi if [ -z "$TLS_CONF" ]; then TLS_CONF="$DOMAIN_PATH/tls.valdation.conf" @@ -4661,6 +4685,7 @@ Commands: --uninstall-cronjob Uninstall the cron job. The 'uninstall' command can do this automatically. --cron Run cron job to renew all the certs. --toPkcs Export the certificate and key to a pfx file. + --toPkcs8 Convert to pkcs8 format. --update-account Update account info. --register-account Register account key. --create-account-key Create an account private key, professional use. @@ -4908,6 +4933,9 @@ _process() { --toPkcs) _CMD="toPkcs" ;; + --toPkcs8) + _CMD="toPkcs8" + ;; --createAccountKey | --createaccountkey | -cak | --create-account-key) _CMD="createAccountKey" ;; @@ -5320,6 +5348,9 @@ _process() { toPkcs) toPkcs "$_domain" "$_password" "$_ecc" ;; + toPkcs8) + toPkcs8 "$_domain" "$_ecc" + ;; createAccountKey) createAccountKey "$_accountkeylength" ;; From 342128a457a5d1124b084d419653dd4957c7c2c8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 25 Feb 2017 21:09:06 +0800 Subject: [PATCH 215/620] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e55265d0..3def82a0 100755 --- a/acme.sh +++ b/acme.sh @@ -4935,7 +4935,7 @@ _process() { ;; --toPkcs8) _CMD="toPkcs8" - ;; + ;; --createAccountKey | --createaccountkey | -cak | --create-account-key) _CMD="createAccountKey" ;; From 4fd63f4e302c381cd167f9e3ed1c4bdc3ba0da2e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 25 Feb 2017 21:22:56 +0800 Subject: [PATCH 216/620] fix ci --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d54faed..7f7e120c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,9 +26,9 @@ install: _old_path="$PATH"; echo "PATH=$PATH"; export PATH=""; - export OPENSSL_BIN="/usr/local/openssl"; + export ACME_OPENSSL_BIN="/usr/local/openssl"; openssl version 2>&1 || true; - $OPENSSL_BIN version 2>&1 || true; + $ACME_OPENSSL_BIN version 2>&1 || true; export PATH="$_old_path"; fi @@ -44,7 +44,7 @@ script: - cd .. - git clone 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" ./letest.sh ; fi - - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi + - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi matrix: From 58e4d337e4eaa93de9ca0fdeb661df5ecdb1e50e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 26 Feb 2017 12:07:06 +0800 Subject: [PATCH 217/620] clear the pending authz when issue error fix bug https://github.com/Neilpang/acme.sh/issues/663 --- acme.sh | 59 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/acme.sh b/acme.sh index 3def82a0..f11f1f07 100755 --- a/acme.sh +++ b/acme.sh @@ -2819,6 +2819,7 @@ _on_before_issue() { _on_issue_err() { _chk_post_hook="$1" + _chk_vlist="$2" _debug _on_issue_err if [ "$LOG_FILE" ]; then _err "Please check log file for more details: $LOG_FILE" @@ -2827,10 +2828,6 @@ _on_issue_err() { _err "See: $_DEBUG_WIKI" fi - if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then - _debug "$(_dlg_versions)" - fi - #run the post hook if [ "$_chk_post_hook" ]; then _info "Run post hook:'$_chk_post_hook'" @@ -2841,6 +2838,28 @@ _on_issue_err() { return 1 fi fi + + #trigger the validation to flush the pending authz + if [ "$_chk_vlist" ]; then + ( + _debug2 "_chk_vlist" "$_chk_vlist" + _debug2 "start to deactivate authz" + ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ') + for ventry in $ventries; do + d=$(echo "$ventry" | cut -d "$sep" -f 1) + keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) + uri=$(echo "$ventry" | cut -d "$sep" -f 3) + vtype=$(echo "$ventry" | cut -d "$sep" -f 4) + _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) + __trigger_validaton "$uri" "$keyauthorization" + done + ) + fi + + if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then + _debug "$(_dlg_versions)" + fi + } _on_issue_success() { @@ -3053,6 +3072,16 @@ __get_domain_new_authz() { } +#uri keyAuthorization +__trigger_validaton() { + _debug2 "tigger domain validation." + _t_url="$1" + _debug2 _t_url "$_t_url" + _t_key_authz="$2" + _debug2 _t_key_authz "$_t_key_authz" + _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" +} + #webroot, domain domainlist keylength issue() { if [ -z "$2" ]; then @@ -3366,7 +3395,7 @@ issue() { _startserver "$keyauthorization" "$_ncaddr" & if [ "$?" != "0" ]; then _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi serverproc="$!" @@ -3382,7 +3411,7 @@ issue() { BACKUP_NGINX_CONF="" if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi @@ -3417,7 +3446,7 @@ issue() { _err "$d:Can not write token to file : $wellknown_path/$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi @@ -3462,16 +3491,16 @@ issue() { _err "Start tls server error." _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi fi - if ! _send_signed_request "$uri" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}"; then + if ! __trigger_validaton "$uri" "$keyauthorization"; then _err "$d:Can not get challenge: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi @@ -3479,7 +3508,7 @@ issue() { _err "$d:Challenge error: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi @@ -3494,7 +3523,7 @@ issue() { _err "$d:Timeout" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err + _on_issue_err "$_post_hook" "$vlist" return 1 fi @@ -3506,7 +3535,7 @@ issue() { _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi _debug2 original "$response" @@ -3541,7 +3570,7 @@ issue() { fi _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi @@ -3551,7 +3580,7 @@ issue() { _err "$d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi From c719a61ea70ad1a19337fe0cbb61c1cc0e80540b Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 26 Feb 2017 12:15:39 +0800 Subject: [PATCH 218/620] fix format --- acme.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/acme.sh b/acme.sh index f11f1f07..ecc6cb24 100755 --- a/acme.sh +++ b/acme.sh @@ -2842,17 +2842,17 @@ _on_issue_err() { #trigger the validation to flush the pending authz if [ "$_chk_vlist" ]; then ( - _debug2 "_chk_vlist" "$_chk_vlist" - _debug2 "start to deactivate authz" - ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ') - for ventry in $ventries; do - d=$(echo "$ventry" | cut -d "$sep" -f 1) - keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) - uri=$(echo "$ventry" | cut -d "$sep" -f 3) - vtype=$(echo "$ventry" | cut -d "$sep" -f 4) - _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) - __trigger_validaton "$uri" "$keyauthorization" - done + _debug2 "_chk_vlist" "$_chk_vlist" + _debug2 "start to deactivate authz" + ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ') + for ventry in $ventries; do + d=$(echo "$ventry" | cut -d "$sep" -f 1) + keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) + uri=$(echo "$ventry" | cut -d "$sep" -f 3) + vtype=$(echo "$ventry" | cut -d "$sep" -f 4) + _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) + __trigger_validaton "$uri" "$keyauthorization" + done ) fi From 7c2e87549496e18c57253428252f8ff67ed73d53 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 26 Feb 2017 22:20:08 +0800 Subject: [PATCH 219/620] fix https://github.com/Neilpang/acme.sh/issues/675 --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index ecc6cb24..724f0e97 100755 --- a/acme.sh +++ b/acme.sh @@ -5277,6 +5277,7 @@ _process() { --openssl-bin) _openssl_bin="$2" ACME_OPENSSL_BIN="$_openssl_bin" + shift ;; *) _err "Unknown parameter : $1" From 81532f375ea6f9b55e19b07bbe1c106f3d164b19 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 27 Feb 2017 13:38:29 +0800 Subject: [PATCH 220/620] fix https://github.com/Neilpang/acme.sh/issues/667#issuecomment-282629936 --- acme.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/acme.sh b/acme.sh index 724f0e97..d2bb6c53 100755 --- a/acme.sh +++ b/acme.sh @@ -927,6 +927,15 @@ _createkey() { _debug "Use length $length" + if ! touch "$f" >/dev/null 2>&1; then + _f_path="$(dirname "$f")" + _debug _f_path "$_f_path" + if ! mkdir -p "$_f_path"; then + _err "Can not create path: $_f_path" + return 1 + fi + fi + if _isEccKey "$length"; then _debug "Using ec name: $eccname" $ACME_OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f" From 9b124070286abde59d5afcffe67a6773c3135a78 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 27 Feb 2017 20:48:48 +0800 Subject: [PATCH 221/620] Wget (#678) * --use-wget force to use wget * fix force wget --- acme.sh | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index d2bb6c53..3e9e4d15 100755 --- a/acme.sh +++ b/acme.sh @@ -1505,7 +1505,7 @@ _post() { _inithttp - if [ "$_ACME_CURL" ]; then + if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then _CURL="$_ACME_CURL" if [ "$HTTPS_INSECURE" ]; then _CURL="$_CURL --insecure " @@ -1572,7 +1572,7 @@ _get() { _inithttp - if [ "$_ACME_CURL" ]; then + if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then _CURL="$_ACME_CURL" if [ "$HTTPS_INSECURE" ]; then _CURL="$_CURL --insecure " @@ -4787,6 +4787,7 @@ Parameters: --listen-v4 Force standalone/tls server to listen at ipv4. --listen-v6 Force standalone/tls server to listen at ipv6. --openssl-bin Specifies a custom openssl bin location. + --use-wget Force to use wget, if you have both curl and wget installed. " } @@ -4865,6 +4866,12 @@ _processAccountConf() { _saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE" fi + if [ "$_use_wget" ]; then + _saveaccountconf "ACME_USE_WGET" "$_use_wget" + elif [ "$ACME_USE_WGET" ]; then + _saveaccountconf "ACME_USE_WGET" "$ACME_USE_WGET" + fi + } _process() { @@ -4909,6 +4916,7 @@ _process() { _listen_v6="" _openssl_bin="" _syslog="" + _use_wget="" while [ ${#} -gt 0 ]; do case "${1}" in @@ -5288,6 +5296,10 @@ _process() { ACME_OPENSSL_BIN="$_openssl_bin" shift ;; + --use-wget) + _use_wget="1" + ACME_USE_WGET="1" + ;; *) _err "Unknown parameter : $1" return 1 From 59f7a2f6efb93fd81098146a0f8fe8367c155eb8 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 27 Feb 2017 20:54:38 +0800 Subject: [PATCH 222/620] Wget (#678) (#679) * --use-wget force to use wget * fix force wget --- acme.sh | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index d2bb6c53..3e9e4d15 100755 --- a/acme.sh +++ b/acme.sh @@ -1505,7 +1505,7 @@ _post() { _inithttp - if [ "$_ACME_CURL" ]; then + if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then _CURL="$_ACME_CURL" if [ "$HTTPS_INSECURE" ]; then _CURL="$_CURL --insecure " @@ -1572,7 +1572,7 @@ _get() { _inithttp - if [ "$_ACME_CURL" ]; then + if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then _CURL="$_ACME_CURL" if [ "$HTTPS_INSECURE" ]; then _CURL="$_CURL --insecure " @@ -4787,6 +4787,7 @@ Parameters: --listen-v4 Force standalone/tls server to listen at ipv4. --listen-v6 Force standalone/tls server to listen at ipv6. --openssl-bin Specifies a custom openssl bin location. + --use-wget Force to use wget, if you have both curl and wget installed. " } @@ -4865,6 +4866,12 @@ _processAccountConf() { _saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE" fi + if [ "$_use_wget" ]; then + _saveaccountconf "ACME_USE_WGET" "$_use_wget" + elif [ "$ACME_USE_WGET" ]; then + _saveaccountconf "ACME_USE_WGET" "$ACME_USE_WGET" + fi + } _process() { @@ -4909,6 +4916,7 @@ _process() { _listen_v6="" _openssl_bin="" _syslog="" + _use_wget="" while [ ${#} -gt 0 ]; do case "${1}" in @@ -5288,6 +5296,10 @@ _process() { ACME_OPENSSL_BIN="$_openssl_bin" shift ;; + --use-wget) + _use_wget="1" + ACME_USE_WGET="1" + ;; *) _err "Unknown parameter : $1" return 1 From fab2d9dc6ada42e2ac15abda2bd2f2ea73cf8bfc Mon Sep 17 00:00:00 2001 From: Frederic Crozat Date: Tue, 28 Feb 2017 12:58:04 +0100 Subject: [PATCH 223/620] add API for Gandi LiveDNS (#680) * add API for Gandi LiveDNS * ensure Gandi API key is saved for renewing certificate. * gandi_livedns: use PUT instead of POST for creating DNS record * gandi_livedns: fix formatting * dns_gandi_livedns: fix shellcheck errors --- README.md | 1 + dnsapi/README.md | 12 ++++ dnsapi/dns_gandi_livedns.sh | 120 ++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100755 dnsapi/dns_gandi_livedns.sh diff --git a/README.md b/README.md index c8aeeb0f..fd867015 100644 --- a/README.md +++ b/README.md @@ -294,6 +294,7 @@ You don't have to do anything manually! 1. FreeDNS (https://freedns.afraid.org/) 1. cyon.ch 1. Domain-Offensive/Resellerinterface/Domainrobot API +1. Gandi LiveDNS API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 7df7142a..7607257d 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -336,6 +336,18 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_do -d example.com -d www.example.com ``` +## 18. Use Gandi LiveDNS API + +You will need your Gandi API key (on your Account preferences, go to Security and generate your API key) and export it before you run `acme.sh`: +``` +export GANDI_LIVEDNS_KEY="fdmlfsdklmfdkmqsdfk" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_gandi_livedns -d example.com -d www.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh new file mode 100755 index 00000000..9a170b8b --- /dev/null +++ b/dnsapi/dns_gandi_livedns.sh @@ -0,0 +1,120 @@ +#!/usr/bin/env sh + +# Gandi LiveDNS v5 API +# http://doc.livedns.gandi.net/ +# currently under beta +# +# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable +# +#Author: Frédéric Crozat +#Report Bugs here: https://github.com/fcrozat/acme.sh +# +######## Public functions ##################### + +GANDI_LIVEDNS_API="https://dns.beta.gandi.net/api/v5" + +#Usage: dns_gandi_livedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_gandi_livedns_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$GANDI_LIVEDNS_KEY" ]; then + _err "No API key specifed for Gandi LiveDNS." + _err "Create your key and export it as GANDI_LIVEDNS_KEY" + return 1 + fi + + _saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + _debug domain "$_domain" + _debug sub_domain "$_sub_domain" + + _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" + + return $? +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_gandi_livedns_rm() { + fulldomain=$1 + txtvalue=$2 + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug fulldomain "$fulldomain" + _debug domain "$_domain" + _debug sub_domain "$_sub_domain" + + _gandi_livedns_rest DELETE "domains/$_domain/records/$_sub_domain/TXT" "" + + return $? +} + +#################### 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) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _gandi_livedns_rest GET "domains/$h"; then + return 1 + fi + + if _contains "$response" '"code": 404'; then + _debug "$h not found" + else + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +_gandi_livedns_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Content-Type: application/json" + export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY" + + if [ "$data" ] || [ "$m" = "DELETE" ]; then + _debug data "$data" + response="$(_post "$data" "$GANDI_LIVEDNS_API/$ep" "" "$m")" + else + response="$(_get "$GANDI_LIVEDNS_API/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From 9683ffe13a08ffee278c74b7059a190e4084f417 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 28 Feb 2017 20:39:23 +0800 Subject: [PATCH 224/620] minor fix error message --- dnsapi/README.md | 3 ++- dnsapi/dns_gandi_livedns.sh | 13 +++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 7607257d..18c1ca9f 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -338,7 +338,8 @@ acme.sh --issue --dns dns_do -d example.com -d www.example.com ## 18. Use Gandi LiveDNS API -You will need your Gandi API key (on your Account preferences, go to Security and generate your API key) and export it before you run `acme.sh`: +You must enable the new Gandi LiveDNS API first and the create your api key, See: http://doc.livedns.gandi.net/ + ``` export GANDI_LIVEDNS_KEY="fdmlfsdklmfdkmqsdfk" ``` diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 9a170b8b..76c4c8a9 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -38,7 +38,6 @@ dns_gandi_livedns_add() { _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" - return $? } #Usage: fulldomain txtvalue @@ -59,7 +58,6 @@ dns_gandi_livedns_rm() { _gandi_livedns_rest DELETE "domains/$_domain/records/$_sub_domain/TXT" "" - return $? } #################### Private functions below ################################## @@ -82,7 +80,10 @@ _get_root() { return 1 fi - if _contains "$response" '"code": 404'; then + if _contains "$response" '"code": 401'; then + _err "$response" + return 1 + elif _contains "$response" '"code": 404'; then _debug "$h not found" else _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) @@ -104,11 +105,11 @@ _gandi_livedns_rest() { export _H1="Content-Type: application/json" export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY" - if [ "$data" ] || [ "$m" = "DELETE" ]; then + if [ "$m" = "GET" ]; then + response="$(_get "$GANDI_LIVEDNS_API/$ep")" + else _debug data "$data" response="$(_post "$data" "$GANDI_LIVEDNS_API/$ep" "" "$m")" - else - response="$(_get "$GANDI_LIVEDNS_API/$ep")" fi if [ "$?" != "0" ]; then From d24a87caf189dbcfaa066645f4076d755afb2a87 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 28 Feb 2017 20:56:11 +0800 Subject: [PATCH 225/620] minor --- dnsapi/dns_gandi_livedns.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 76c4c8a9..d2521941 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -37,7 +37,7 @@ dns_gandi_livedns_add() { _debug sub_domain "$_sub_domain" _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" - + _contains "$response" '{"message": "Zone Record Created"}' } #Usage: fulldomain txtvalue @@ -71,6 +71,7 @@ _get_root() { 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 From 39a1f1ef644cef0daeb8fffa94cc8d844e207639 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 28 Feb 2017 21:04:33 +0800 Subject: [PATCH 226/620] fix 404 for wget --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 3e9e4d15..a8b3e038 100755 --- a/acme.sh +++ b/acme.sh @@ -1610,7 +1610,7 @@ _get() { fi ret=$? if [ "$_ret" = "8" ]; then - _ret=0 + ret=0 _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later." fi if [ "$ret" != "0" ]; then From f731a4c7041416612ffdf593f9d5763a850c09ac Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 28 Feb 2017 21:06:02 +0800 Subject: [PATCH 227/620] fix 404 for wget --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index a8b3e038..b87df6d6 100755 --- a/acme.sh +++ b/acme.sh @@ -1609,7 +1609,7 @@ _get() { $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - "$url" fi ret=$? - if [ "$_ret" = "8" ]; then + if [ "$ret" = "8" ]; then ret=0 _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later." fi From 810c129ca970b7ae26e1e648f90670b8d91d2beb Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 28 Feb 2017 21:08:20 +0800 Subject: [PATCH 228/620] minor fix error message --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index b87df6d6..a18be6f4 100755 --- a/acme.sh +++ b/acme.sh @@ -1546,7 +1546,7 @@ _post() { _ret="$?" if [ "$_ret" = "8" ]; then _ret=0 - _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later." + _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" @@ -1611,7 +1611,7 @@ _get() { ret=$? if [ "$ret" = "8" ]; then ret=0 - _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later." + _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" From 177b57e1c007f185c87e9791c6f31b68ba0b302e Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 28 Feb 2017 21:35:20 +0800 Subject: [PATCH 229/620] fix wget content on 404 error --- acme.sh | 5 +++++ dnsapi/dns_gandi_livedns.sh | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index a18be6f4..7c2875fd 100755 --- a/acme.sh +++ b/acme.sh @@ -1485,6 +1485,11 @@ _inithttp() { fi fi + #from wget 1.14: do not skip body on 404 error + if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help)" "--content-on-error"; then + _ACME_WGET="$_ACME_WGET --content-on-error " + fi + __HTTP_INITIALIZED=1 } diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index d2521941..55218a20 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -36,8 +36,9 @@ 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": "Zone Record Created"}' + _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \ + && _contains "$response" '{"message": "Zone Record Created"}' \ + && _info "Add $(__green "success")" } #Usage: fulldomain txtvalue From 58ef6d83852f5bffc6ad00311a139f5f60ec4a2b Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 1 Mar 2017 13:12:29 +0800 Subject: [PATCH 230/620] fix wget error message --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 7c2875fd..0313e0e1 100755 --- a/acme.sh +++ b/acme.sh @@ -1486,7 +1486,7 @@ _inithttp() { fi #from wget 1.14: do not skip body on 404 error - if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help)" "--content-on-error"; then + if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help 2>&1)" "--content-on-error"; then _ACME_WGET="$_ACME_WGET --content-on-error " fi From 839f18d052c0dff1d6e38c098087e68832788f39 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 1 Mar 2017 19:17:20 +0800 Subject: [PATCH 231/620] fix format --- dnsapi/dns_gandi_livedns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 55218a20..41f42980 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -37,8 +37,8 @@ dns_gandi_livedns_add() { _debug sub_domain "$_sub_domain" _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \ - && _contains "$response" '{"message": "Zone Record Created"}' \ - && _info "Add $(__green "success")" + && _contains "$response" '{"message": "Zone Record Created"}' \ + && _info "Add $(__green "success")" } #Usage: fulldomain txtvalue From 29992f54a35394a9c4d75bb52e75b3c702b2b5b9 Mon Sep 17 00:00:00 2001 From: nytral Date: Wed, 1 Mar 2017 18:28:39 +0100 Subject: [PATCH 232/620] delete support for dns_me --- dnsapi/dns_me.sh | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index f63621d9..59e9cec7 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -78,7 +78,41 @@ dns_me_add() { #fulldomain dns_me_rm() { fulldomain=$1 + txtvalue=$2 + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + _debug "Getting txt records" + _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" + + if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2) + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | head -n 1) + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _me_rest DELETE "$_domain_id/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" '"success":true' + fi } #################### Private functions below ################################## @@ -130,7 +164,7 @@ _me_rest() { export _H2="x-dnsme-requestDate: $cdate" export _H3="x-dnsme-hmac: $hmac" - if [ "$data" ]; then + if [ "$m" != "GET" ]; then _debug data "$data" response="$(_post "$data" "$ME_Api/$ep" "" "$m")" else From a1e1bfc71b24ee04856230e2a28e27b746652cd6 Mon Sep 17 00:00:00 2001 From: nytral Date: Wed, 1 Mar 2017 19:20:16 +0100 Subject: [PATCH 233/620] removed useless code --- dnsapi/dns_me.sh | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 59e9cec7..7c4a2ae3 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -91,11 +91,6 @@ dns_me_rm() { _debug "Getting txt records" _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" - if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then - _err "Error" - return 1 - fi - count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2) _debug count "$count" if [ "$count" = "0" ]; then @@ -107,10 +102,7 @@ dns_me_rm() { _err "Can not get record id to remove." return 1 fi - if ! _me_rest DELETE "$_domain_id/records/$record_id"; then - _err "Delete record error." - return 1 - fi + _me_rest DELETE "$_domain_id/records/$record_id" _contains "$response" '"success":true' fi } From 8d53ec53530cb204bd873e2984df6300e4cb2392 Mon Sep 17 00:00:00 2001 From: nytral Date: Wed, 1 Mar 2017 19:38:02 +0100 Subject: [PATCH 234/620] fixed validation, added LUA while I'm at it --- dnsapi/dns_lua.sh | 31 ++++++++++++++++++++++++++++++- dnsapi/dns_me.sh | 7 +++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_lua.sh b/dnsapi/dns_lua.sh index 828e8012..00c54430 100755 --- a/dnsapi/dns_lua.sh +++ b/dnsapi/dns_lua.sh @@ -81,7 +81,36 @@ dns_lua_add() { #fulldomain dns_lua_rm() { fulldomain=$1 + txtvalue=$2 + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _LUA_rest GET "zones/${_domain_id}/records" + count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1) + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _LUA_rest DELETE "/zones/$_domain_id/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" "$record_id" + fi } #################### Private functions below ################################## @@ -129,7 +158,7 @@ _LUA_rest() { export _H1="Accept: application/json" export _H2="Authorization: Basic $LUA_auth" - if [ "$data" ]; then + if [ "$m" != "GET" ]; then _debug data "$data" response="$(_post "$data" "$LUA_Api/$ep" "" "$m")" else diff --git a/dnsapi/dns_me.sh b/dnsapi/dns_me.sh index 7c4a2ae3..3393fb75 100644 --- a/dnsapi/dns_me.sh +++ b/dnsapi/dns_me.sh @@ -102,8 +102,11 @@ dns_me_rm() { _err "Can not get record id to remove." return 1 fi - _me_rest DELETE "$_domain_id/records/$record_id" - _contains "$response" '"success":true' + if ! _me_rest DELETE "$_domain_id/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" '' fi } From 51f8bec81b7db02217d118c9b6a82b45a2aabcb1 Mon Sep 17 00:00:00 2001 From: Felix Wolfsteller Date: Thu, 2 Mar 2017 08:38:25 +0100 Subject: [PATCH 235/620] deploy apache script: fix comment (dovecot/apache) --- deploy/apache.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/apache.sh b/deploy/apache.sh index b6c1fbc2..7b34bd5f 100644 --- a/deploy/apache.sh +++ b/deploy/apache.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -#Here is a script to deploy cert to dovecot server. +#Here is a script to deploy cert to apache server. #returns 0 means success, otherwise error. From 5288c54aade8f54e4b4ec50f7c44513bc32cc11b Mon Sep 17 00:00:00 2001 From: Felix Wolfsteller Date: Thu, 2 Mar 2017 08:38:25 +0100 Subject: [PATCH 236/620] deploy apache script: fix comment (dovecot/apache) Closes #690 . --- deploy/apache.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/apache.sh b/deploy/apache.sh index b6c1fbc2..7b34bd5f 100644 --- a/deploy/apache.sh +++ b/deploy/apache.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -#Here is a script to deploy cert to dovecot server. +#Here is a script to deploy cert to apache server. #returns 0 means success, otherwise error. From e735d8d4e5a0dd7810dd6cc937fec93c8fdbaad2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 3 Mar 2017 22:03:19 +0800 Subject: [PATCH 237/620] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 0313e0e1..38bed5f6 100755 --- a/acme.sh +++ b/acme.sh @@ -146,7 +146,7 @@ _dlg_versions() { echo "apache:" if [ "$_APACHECTL" ] && _exists "$_APACHECTL"; then - _APACHECTL -V 2>&1 + $_APACHECTL -V 2>&1 else echo "apache doesn't exists." fi From 6fb2a1ed39c263407c2d1bb6d8b2e8a0cd9a7d07 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 5 Mar 2017 19:56:06 +0800 Subject: [PATCH 238/620] minor fix comments --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 38bed5f6..d6ed13a4 100755 --- a/acme.sh +++ b/acme.sh @@ -1279,12 +1279,12 @@ _url_replace() { } _time2str() { - #BSD + #Linux if date -u -d@"$1" 2>/dev/null; then return fi - #Linux + #BSD if date -u -r "$1" 2>/dev/null; then return fi From 9c87a5890dec74d7f0c7f0edac9b72699e7aa116 Mon Sep 17 00:00:00 2001 From: csmk Date: Sun, 5 Mar 2017 22:18:31 +0900 Subject: [PATCH 239/620] Add support for Knot DNS API The script is actually an adapted version of the `dns_nsupdate.sh` script, as the `knsupdate` utility is quite similar to `nsupdate`. --- README.md | 1 + dnsapi/README.md | 45 ++++++++++++++++++++++ dnsapi/dns_knot.sh | 95 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 dnsapi/dns_knot.sh diff --git a/README.md b/README.md index fd867015..3a03e703 100644 --- a/README.md +++ b/README.md @@ -295,6 +295,7 @@ You don't have to do anything manually! 1. cyon.ch 1. Domain-Offensive/Resellerinterface/Domainrobot API 1. Gandi LiveDNS API +1. Knot DNS API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 18c1ca9f..5b71e89f 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -349,6 +349,51 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_gandi_livedns -d example.com -d www.example.com ``` +## 19. Use Knot (knsupdate) DNS API to automatically issue cert + +First, generate a TSIG key for updating the zone. + +``` +keymgr tsig generate acme_key algorithm hmac-sha512 > /etc/knot/acme.key +``` + +Include this key in your knot configuration file. + +``` +include: /etc/knot/acme.key +``` + +Next, configure your zone to allow dynamic updates. + +Dynamic updates for the zone are allowed via proper ACL rule with the `update` action. For in-depth instructions, please see [Knot DNS's documentation](https://www.knot-dns.cz/documentation/). + +``` +acl: + - id: acme_acl + address: 192.168.1.0/24 + key: acme_key + action: update + +zone: + - domain: example.com + file: example.com.zone + acl: acme_acl +``` + +Finally, make the DNS server and TSIG Key available to `acme.sh` + +``` +export KNOT_SERVER="dns.example.com" +export KNOT_KEY=`grep \# /etc/knot/acme.key | cut -d' ' -f2` +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_knot -d example.com -d www.example.com +``` + +The `KNOT_SERVER` and `KNOT_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_knot.sh b/dnsapi/dns_knot.sh new file mode 100644 index 00000000..b6d1e0b6 --- /dev/null +++ b/dnsapi/dns_knot.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env sh + +######## Public functions ##################### + +#Usage: dns_knot_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_knot_add() { + fulldomain=$1 + txtvalue=$2 + _checkKey || return 1 + [ -n "${KNOT_SERVER}" ] || KNOT_SERVER="localhost" + # save the dns server and key to the account.conf file. + _saveaccountconf KNOT_SERVER "${KNOT_SERVER}" + _saveaccountconf KNOT_KEY "${KNOT_KEY}" + + if ! _get_root "$fulldomain"; then + _err "Domain does not exist." + return 1 + fi + + _info "Adding ${fulldomain}. 60 TXT \"${txtvalue}\"" + + knsupdate -y "${KNOT_KEY}" < Date: Mon, 6 Mar 2017 11:09:12 +0900 Subject: [PATCH 240/620] deploy for OSX Keychain --- deploy/keychain.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 deploy/keychain.sh diff --git a/deploy/keychain.sh b/deploy/keychain.sh new file mode 100644 index 00000000..a99ed465 --- /dev/null +++ b/deploy/keychain.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env sh + +#Here is a sample custom api script. +#This file name is "myapi.sh" +#So, here must be a method myapi_deploy() +#Which will be called by acme.sh to deploy the cert +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +keychain_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + /usr/bin/security import "$_ckey" -k "/Library/Keychains/System.keychain" + /usr/bin/security import "$_ccert" -k "/Library/Keychains/System.keychain" + /usr/bin/security import "$_cca" -k "/Library/Keychains/System.keychain" + /usr/bin/security import "$_cfullchain" -k "/Library/Keychains/System.keychain" + + return 0 +} From f589a1d2458556fbbd8dfc8cff758b2f666d7f38 Mon Sep 17 00:00:00 2001 From: csmk Date: Tue, 7 Mar 2017 22:21:22 +0900 Subject: [PATCH 241/620] Fix format: use double quote to prevent globbing and word splitting --- dnsapi/dns_knot.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_knot.sh b/dnsapi/dns_knot.sh index b6d1e0b6..094a6981 100644 --- a/dnsapi/dns_knot.sh +++ b/dnsapi/dns_knot.sh @@ -73,10 +73,10 @@ EOF _get_root() { domain=$1 i="$(echo "$fulldomain" | tr '.' ' ' | wc -w)" - i=$(_math $i - 1) + 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 fi From bce11af09ae31284afc0d07e6205113f5390b207 Mon Sep 17 00:00:00 2001 From: hiska Date: Wed, 8 Mar 2017 08:00:17 +0900 Subject: [PATCH 242/620] Update README.md for OSX Keychain --- deploy/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/deploy/README.md b/deploy/README.md index 4a13e096..d8c2f57c 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -72,3 +72,8 @@ 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 +``` From 5378d9ca2655543cdf765065d0f3434b5e5ded0f Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 8 Mar 2017 13:55:01 +0800 Subject: [PATCH 243/620] fix nginx mode --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index d6ed13a4..4edc1ecf 100755 --- a/acme.sh +++ b/acme.sh @@ -2462,7 +2462,7 @@ _setNginx() { fi _debug "Start detect nginx conf for $_d from:$_start_f" if ! _checkConf "$_d" "$_start_f"; then - "Can not find conf file for domain $d" + _err "Can not find conf file for domain $d" return 1 fi _info "Found conf file: $FOUND_REAL_NGINX_CONF" @@ -2559,7 +2559,7 @@ _checkConf() { FOUND_REAL_NGINX_CONF="$2" return 0 fi - if grep "^ *include *.*;" "$2" >/dev/null; then + if cat "$2" | tr "\t" " " | grep "^ *include *.*;" >/dev/null; then _debug "Try include files" for included in $(grep "^ *include *.*;" "$2" | sed "s/include //" | tr -d " ;"); do _debug "check included $included" From f08a79d3724b8c374131a28862b954738a8085b4 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 8 Mar 2017 16:01:14 +0800 Subject: [PATCH 244/620] fix nginx mode --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 4edc1ecf..eb1a8969 100755 --- a/acme.sh +++ b/acme.sh @@ -2546,7 +2546,7 @@ _checkConf() { if [ ! -f "$2" ] && ! echo "$2" | grep '*$' >/dev/null && echo "$2" | grep '*' >/dev/null; then _debug "wildcard" for _w_f in $2; do - if _checkConf "$1" "$_w_f"; then + if [ -f "$_w_f"] && _checkConf "$1" "$_w_f"; then return 0 fi done @@ -2559,9 +2559,9 @@ _checkConf() { FOUND_REAL_NGINX_CONF="$2" return 0 fi - if cat "$2" | tr "\t" " " | grep "^ *include *.*;" >/dev/null; then + if cat "$2" | tr "\t" " " | grep "^ *include *.*;" >/dev/null; then _debug "Try include files" - for included in $(grep "^ *include *.*;" "$2" | sed "s/include //" | tr -d " ;"); do + for included in $(cat "$2" | tr "\t" " " | grep "^ *include *.*;" | sed "s/include //" | tr -d " ;"); do _debug "check included $included" if _checkConf "$1" "$included"; then return 0 From 6f1c72f5b46f7f0ee114c873886496a8ccb6139b Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 8 Mar 2017 21:21:15 +0800 Subject: [PATCH 245/620] add links --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index fd867015..e851fb93 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,18 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) # [中文说明](https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E) +# Who are using **acme.sh** +- [FreeBSD.org](https://blog.crashed.org/letsencrypt-in-freebsd-org/) +- [ruby-china.org](https://ruby-china.org/topics/31983) +- [Proxmox](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x_and_newer)) +- [pfsense](https://github.com/pfsense/FreeBSD-ports/pull/89) +- [webfaction](https://community.webfaction.com/questions/19988/using-letsencrypt) +- [Loadbalancer.org](https://www.loadbalancer.org/blog/loadbalancer-org-with-lets-encrypt-quick-and-dirty) +- [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709) +- [Centminmod](http://centminmod.com/letsencrypt-acmetool-https.html) +- [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) +- [archlinux](https://aur.archlinux.org/packages/acme.sh-git/) +- [more and more](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) # Tested OS From 63ec05a66c71cef8ea71e8e6c6c152acb8c1ae2a Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 8 Mar 2017 21:23:12 +0800 Subject: [PATCH 246/620] fix links --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e851fb93..450de49a 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) - [Centminmod](http://centminmod.com/letsencrypt-acmetool-https.html) - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) - [archlinux](https://aur.archlinux.org/packages/acme.sh-git/) -- [more and more](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) +- [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) # Tested OS From c4bf5eef73aa749393101f50683e4391ac8e46d2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 8 Mar 2017 21:51:25 +0800 Subject: [PATCH 247/620] add _upper_case and _lower_case --- acme.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/acme.sh b/acme.sh index eb1a8969..699ea268 100755 --- a/acme.sh +++ b/acme.sh @@ -299,6 +299,16 @@ _secure_debug3() { fi } +_upper_case() { + # shellcheck disable=SC2018,SC2019 + tr 'a-z' 'A-Z' +} + +_lower_case() { + # shellcheck disable=SC2018,SC2019 + tr 'A-Z' 'a-z' +} + _startswith() { _str="$1" _sub="$2" From 7d0452c7e330c53dd810964c7590876348642c75 Mon Sep 17 00:00:00 2001 From: nytral Date: Wed, 8 Mar 2017 22:12:37 +0100 Subject: [PATCH 248/620] added NS1. support --- README.md | 1 + dnsapi/README.md | 11 +++ dnsapi/dns_nsone.sh | 159 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 dnsapi/dns_nsone.sh diff --git a/README.md b/README.md index 7d5ab846..5d1ddc5b 100644 --- a/README.md +++ b/README.md @@ -308,6 +308,7 @@ You don't have to do anything manually! 1. Domain-Offensive/Resellerinterface/Domainrobot API 1. Gandi LiveDNS API 1. Knot DNS API +1. NS1. API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 5b71e89f..c1e98a6a 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -394,6 +394,17 @@ 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 NS1. 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 +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh new file mode 100644 index 00000000..6a7d6001 --- /dev/null +++ b/dnsapi/dns_nsone.sh @@ -0,0 +1,159 @@ +#!/usr/bin/env sh + +# bug reports to dev@1e.ca + +# +#NS1_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#NS1_Email="user@luadns.net" + +NS1_Api="https://api.nsone.net/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_nsone_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$NS1_Key" ]; then + NS1_Key="" + _err "You didn't specify nsone dns api key yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf NS1_Key "$NS1_Key" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _nsone_rest GET "zones/${_domain}" + + if ! _contains "$response" "\"records\":"; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Adding record" + + if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\"}"; then + if _contains "$response" "$fulldomain"; then + _info "Added" + #todo: check if the record takes effect + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + record_id=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\",\"id\":\"[^,]*\"" | _head_n 1 | cut -d: -f7 | cut -d, -f1) + _debug "record_id" "$record_id" + + _nsone_rest POST "zones/$_domain_/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}" + if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then + _info "Updated!" + #todo: check if the record takes effect + return 0 + fi + _err "Update error" + return 1 + fi + +} + +#fulldomain +dns_nsone_rm() { + fulldomain=$1 + txtvalue=$2 + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _nsone_rest GET "zones/${_domain}/$fulldomain/TXT" + + count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",.*\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + if ! _nsone_rest DELETE "zones/${_domain}/$fulldomain/TXT"; then + _err "Delete record error." + return 1 + fi + _contains "$response" "" + fi +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + if ! _nsone_rest GET "zones"; then + return 1 + fi + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "\"zone\":\"$h\""; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_nsone_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Accept: application/json" + export _H2="X-NSONE-Key: $NS1_Key" + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$NS1_Api/$ep" "" "$m")" + else + response="$(_get "$NS1_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From 17361df66b9f8a4a4aabc7b1ab789d7d3ef5bb47 Mon Sep 17 00:00:00 2001 From: nytral Date: Wed, 8 Mar 2017 22:15:07 +0100 Subject: [PATCH 249/620] cleanup --- dnsapi/dns_nsone.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index 6a7d6001..898319b4 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -5,7 +5,6 @@ # #NS1_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" # -#NS1_Email="user@luadns.net" NS1_Api="https://api.nsone.net/v1" From d3c4cd8270d2ee84e2dd20976156b7bdfdce42df Mon Sep 17 00:00:00 2001 From: nytral Date: Wed, 8 Mar 2017 22:21:25 +0100 Subject: [PATCH 250/620] bugfix --- dnsapi/dns_nsone.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index 898319b4..a5ea05fe 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -41,7 +41,7 @@ dns_nsone_add() { return 1 fi - count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ") + count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ") _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" From 1e5e03cc4603a65d4bb0b0d2c3932cbe070e5b96 Mon Sep 17 00:00:00 2001 From: nytral Date: Wed, 8 Mar 2017 22:22:48 +0100 Subject: [PATCH 251/620] typo... --- dnsapi/dns_nsone.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index a5ea05fe..0f6e441a 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -62,7 +62,7 @@ dns_nsone_add() { record_id=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\",\"id\":\"[^,]*\"" | _head_n 1 | cut -d: -f7 | cut -d, -f1) _debug "record_id" "$record_id" - _nsone_rest POST "zones/$_domain_/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}" + _nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}" if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then _info "Updated!" #todo: check if the record takes effect From ac690fceaf5a1fcba7632d340e709258f4fdbc3f Mon Sep 17 00:00:00 2001 From: thewer Date: Thu, 9 Mar 2017 22:28:30 +1000 Subject: [PATCH 252/620] Added DigitalOcean (native) API that requires only a read/write API key for DigitalOcean, updated 2 reads files. --- README.md | 1 + dnsapi/README.md | 13 +++ dnsapi/dns_dgon.sh | 205 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100755 dnsapi/dns_dgon.sh diff --git a/README.md b/README.md index 7d5ab846..52231d0f 100644 --- a/README.md +++ b/README.md @@ -308,6 +308,7 @@ You don't have to do anything manually! 1. Domain-Offensive/Resellerinterface/Domainrobot API 1. Gandi LiveDNS API 1. Knot DNS API +1. DigitalOcean API (native) **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 5b71e89f..fe243cb5 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -394,6 +394,19 @@ 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 +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_dgon.sh b/dnsapi/dns_dgon.sh new file mode 100755 index 00000000..9ceede44 --- /dev/null +++ b/dnsapi/dns_dgon.sh @@ -0,0 +1,205 @@ +#!/usr/bin/env sh + +## Will be called by acme.sh to add the txt record to your api system. +## returns 0 means success, otherwise error. + +## Author: thewer +## GitHub: https://github.com/gitwer/acme.sh + +## +## Environment Variables Required: +## +## DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc" +## + +##################### Public functions ##################### + +## Create the text record for validation. +## Usage: fulldomain txtvalue +## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs" +dns_dgon_add() { + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + _info "Using digitalocean dns validation - add record" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ## save the env vars (key and domain split location) for later automated use + _saveaccountconf DO_API_KEY "$DO_API_KEY" + + ## split the domain for DO API + if ! _get_base_domain "$fulldomain"; then + _err "domain not found in your account for addition" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + ## Set the header with our post type and key auth key + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $DO_API_KEY" + PURL='https://api.digitalocean.com/v2/domains/'$_domain'/records' + PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'"}' + + _debug PURL "$PURL" + _debug PBODY "$PBODY" + + ## the create request - post + ## args: BODY, URL, [need64, httpmethod] + response="$(_post "$PBODY" "$PURL")" + + ## check response + if [ "$?" != "0" ]; then + _err "error in response: $response" + return 1 + fi + _debug2 response "$response" + + ## finished correctly + return 0 +} + +## Remove the txt record after validation. +## Usage: fulldomain txtvalue +## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs" +dns_dgon_rm() { + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + _info "Using digitalocean dns validation - remove record" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ## split the domain for DO API + if ! _get_base_domain "$fulldomain"; then + _err "domain not found in your account for removal" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + ## Set the header with our post type and key auth key + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $DO_API_KEY" + ## get URL for the list of domains + ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}} + GURL="https://api.digitalocean.com/v2/domains/$_domain/records" + + ## while we dont have a record ID we keep going + while [ -z "$record" ]; do + ## 1) get the URL + ## the create request - get + ## args: URL, [onlyheader, timeout] + domain_list="$(_get "$GURL")" + ## 2) find record + ## check for what we are looing for: "type":"A","name":"$_sub_domain" + record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*\d+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")" + ## 3) check record and get next page + if [ -z "$record" ]; then + ## find the next page if we dont have a match + nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=\d+")" + if [ -z "$nextpage" ]; then + _err "no record and no nextpage in digital ocean DNS removal" + return 1 + fi + _debug2 nextpage "$nextpage" + GURL="$nextpage" + fi + ## we break out of the loop when we have a record + done + + ## we found the record + rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*\d+" | _egrep_o "\d+")" + _debug rec_id "$rec_id" + + ## delete the record + ## delete URL for removing the one we dont want + DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id" + + ## the create request - delete + ## args: BODY, URL, [need64, httpmethod] + response="$(_post "" "$DURL" "" "DELETE")" + + ## check response (sort of) + if [ "$?" != "0" ]; then + _err "error in remove response: $response" + return 1 + fi + _debug2 response "$response" + + ## finished correctly + return 0 +} + +##################### Private functions below ##################### + +## Split the domain provided into the "bade domain" and the "start prefix". +## This function searches for the longest subdomain in your account +## for the full domain given and splits it into the base domain (zone) +## and the prefix/record to be added/removed +## USAGE: fulldomain +## EG: "_acme-challenge.two.three.four.domain.com" +## returns +## _sub_domain="_acme-challenge.two" +## _domain="three.four.domain.com" *IF* zone "three.four.domain.com" exists +## if only "domain.com" exists it will return +## _sub_domain="_acme-challenge.two.three.four" +## _domain="domain.com" +_get_base_domain() { + # args + fulldomain="$(echo "$1" | tr '[:upper:]' '[:lower:]')" + _debug fulldomain "$fulldomain" + + # domain max legal length = 253 + MAX_DOM=255 + + ## get a list of domains for the account to check thru + ## Set the headers + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $DO_API_KEY" + _debug DO_API_KEY "$DO_API_KEY" + ## get URL for the list of domains + ## havent seen this request paginated, tested with 18 domains (more requres manual requests with DO) + DOMURL="https://api.digitalocean.com/v2/domains" + + ## get the domain list (DO gives basically a full XFER!) + domain_list="$(_get "$DOMURL")" + + ## check response + if [ "$?" != "0" ]; then + _err "error in domain_list response: $domain_list" + return 1 + fi + _debug2 domain_list "$domain_list" + + ## for each shortening of our $fulldomain, check if it exists in the $domain_list + ## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge" + i=2 + while [ $i -gt 0 ]; do + ## get next longest domain + _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM") + ## check we got something back from our cut (or are we at the end) + if [ -z "$_domain" ]; then + ## we got to the end of the domain - invalid domain + _err "domain not found in DigitalOcean account" + return 1 + fi + ## we got part of a domain back - grep it out + found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")" + ## check if it exists + if [ ! -z "$found" ]; then + ## exists - exit loop returning the parts + sub_point=$(_math $i - 1) + _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point") + _debug _domain "$_domain" + _debug _sub_domain "$_sub_domain" + return 0 + fi + ## increment cut point $i + i=$(_math $i + 1) + done + + ## we went through the entire domain zone list and dint find one that matched + ## doesnt look like we can add in the record + _err "domain not found in DigitalOcean account, but we should never get here" + return 1 +} From 04683338a21bda18da6d3dafce6167de1fb699f2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 11 Mar 2017 10:06:40 +0800 Subject: [PATCH 253/620] fix cloudxns api https://github.com/Neilpang/acme.sh/issues/717 --- dnsapi/dns_cx.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_cx.sh b/dnsapi/dns_cx.sh index 2b6d5691..e2f0f099 100755 --- a/dnsapi/dns_cx.sh +++ b/dnsapi/dns_cx.sh @@ -209,8 +209,7 @@ _rest() { return 1 fi _debug2 response "$response" - if ! _contains "$response" '"message":"success"'; then - return 1 - fi - return 0 + + _contains "$response" '"code":1' + } From 4dd646a424a0f91267f3c198437319548dfb66be Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 13 Mar 2017 11:18:04 +0800 Subject: [PATCH 254/620] fix https://github.com/Neilpang/acme.sh/issues/719 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 699ea268..7906aa4c 100755 --- a/acme.sh +++ b/acme.sh @@ -4628,7 +4628,7 @@ install() { #Modify shebang if _exists bash; then _info "Good, bash is found, so change the shebang to use bash as preferred." - _shebang='#!/usr/bin/env bash' + _shebang='#!'"$(env bash -c "command -v bash")" _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" for subf in $_SUB_FOLDERS; do if [ -d "$LE_WORKING_DIR/$subf" ]; then From 3b7fbcd0c322b152d566dc65a6bca97cc483d4d5 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 13:24:09 +0200 Subject: [PATCH 255/620] Add DNS API support for ClouDNS --- dnsapi/README.md | 14 ++++ dnsapi/dns_cloudns.sh | 158 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100755 dnsapi/dns_cloudns.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index fe243cb5..702efc1c 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -407,6 +407,20 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_dgon -d example.com -d www.example.com ``` +## 21. Use ClouDNS API + +You need to set the HTTP API user ID and password credentials. See: https://www.cloudns.net/wiki/article/42/ + +``` +export CLOUDNS_AUTH_ID=XXXXX +export CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh new file mode 100755 index 00000000..9b93b1ca --- /dev/null +++ b/dnsapi/dns_cloudns.sh @@ -0,0 +1,158 @@ +#!/usr/bin/env sh + +#CLOUDNS_AUTH_ID=XXXXX +#CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" +CLOUDNS_API="https://api.cloudns.net" + +######## Public functions ##################### + +#Usage: dns_cloudns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_cloudns_add() { + _info "Using cloudns" + + if ! _dns_cloudns_init_check; then + return 1 + fi + + zone="$(_dns_cloudns_get_zone_name $1)" + if [ -z "$zone" ]; then + _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." + return 1 + fi + + host="$(echo $1|sed "s/\.$zone\$//")" + record=$2 + record_id=$(_dns_cloudns_get_record_id "$zone" "$host") + + _debug zone "$zone" + _debug host "$host" + _debug record "$record" + _debug record_id "$record_id" + + + if [ -z "$record_id" ]; then + _info "Adding the TXT record for $1" + _dns_cloudns_http_api_call "dns/add-record.json" "domain-name=$zone&record-type=TXT&host=$host&record=$record&ttl=60" + if ! _contains "$response" "\"status\":\"Success\""; then + _err "Record cannot be added." + return 1 + fi + _info "Added." + else + _info "Updating the TXT record for $1" + _dns_cloudns_http_api_call "dns/mod-record.json" "domain-name=$zone&record-id=$record_id&record-type=TXT&host=$host&record=$record&ttl=60" + if ! _contains "$response" "\"status\":\"Success\""; then + _err "The TXT record for $1 cannot be updated." + return 1 + fi + _info "Updated." + fi + + return 0 +} + +#Usage: dns_cloudns_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_cloudns_rm() { + _info "Using cloudns" + + if ! _dns_cloudns_init_check; then + return 1 + fi + + if [ -z $zone]; then + zone="$(_dns_cloudns_get_zone_name $1)" + if [ -z "$zone" ]; then + _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." + return 1 + fi + fi + + host="$(echo $1|sed "s/\.$zone\$//")" + record=$2 + record_id=$(_dns_cloudns_get_record_id "$zone" "$host") + + _debug zone "$zone" + _debug host "$host" + _debug record "$record" + _debug record_id "$record_id" + + if [ ! -z "$record_id" ]; then + _info "Deleting the TXT record for $1" + _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=" + if ! _contains "$response" "\"status\":\"Success\""; then + _err "The TXT record for $1 cannot be deleted." + return 1 + fi + _info "Deleted." + fi + return 0 +} + +#################### Private functions below ################################## +_dns_cloudns_init_check() { + if [ ! -z $CLOUDNS_INIT_CHECK_COMPLETED]; then + return 0 + fi + + if [ -z "$CLOUDNS_AUTH_ID" ]; then + _err "CLOUDNS_AUTH_ID is not configured" + return 1 + fi + + if [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then + _err "CLOUDNS_AUTH_PASSWORD is not configured" + return 1 + fi + + CLOUDNS_INIT_CHECK_COMPLETED=1 + + return 0 +} + +_dns_cloudns_get_zone_name() { + i=2 + while true; do + zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) + + if [ -z "$zoneForCheck" ]; then + # missing zone + return 1; + fi + + _debug zoneForCheck $zoneForCheck + + _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" + + if ! _contains "$response" "\"status\":\"Failed\""; then + echo $zoneForCheck + return 0; + fi + + i=$(expr $i + 1) + done + return 1; +} + +_dns_cloudns_get_record_id() { + _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" + if _contains "$response" "\"id\":"; then + echo $response | awk 'BEGIN { FS="\"" } {print $2}' + return 0 + fi + return 1 +} + +_dns_cloudns_http_api_call () { + method=$1 + + _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" + _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" + + data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" + + response="$(_get "$CLOUDNS_API/$method?$data")" + + _debug response "$response" + + return 1; +} \ No newline at end of file From c7257e0a3c6b4883a1ccde8dbcf4338483d26f48 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:20:58 +0200 Subject: [PATCH 256/620] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 9b93b1ca..39d8c3a6 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -7,20 +7,20 @@ CLOUDNS_API="https://api.cloudns.net" ######## Public functions ##################### #Usage: dns_cloudns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cloudns_add() { +dns_cloudns_add () { _info "Using cloudns" if ! _dns_cloudns_init_check; then - return 1 + return 1 fi zone="$(_dns_cloudns_get_zone_name $1)" if [ -z "$zone" ]; then - _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." - return 1 + _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." + return 1 fi - host="$(echo $1|sed "s/\.$zone\$//")" + host="$(echo $1 | sed "s/\.$zone\$//")" record=$2 record_id=$(_dns_cloudns_get_record_id "$zone" "$host") @@ -52,14 +52,14 @@ dns_cloudns_add() { } #Usage: dns_cloudns_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cloudns_rm() { +dns_cloudns_rm () { _info "Using cloudns" if ! _dns_cloudns_init_check; then return 1 fi - if [ -z $zone]; then + if [ -z $zone ]; then zone="$(_dns_cloudns_get_zone_name $1)" if [ -z "$zone" ]; then _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." @@ -89,8 +89,8 @@ dns_cloudns_rm() { } #################### Private functions below ################################## -_dns_cloudns_init_check() { - if [ ! -z $CLOUDNS_INIT_CHECK_COMPLETED]; then +_dns_cloudns_init_check () { + if [ ! -z $CLOUDNS_INIT_CHECK_COMPLETED ]; then return 0 fi @@ -109,14 +109,13 @@ _dns_cloudns_init_check() { return 0 } -_dns_cloudns_get_zone_name() { +_dns_cloudns_get_zone_name () { i=2 while true; do zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) if [ -z "$zoneForCheck" ]; then - # missing zone - return 1; + return 1 fi _debug zoneForCheck $zoneForCheck @@ -125,15 +124,15 @@ _dns_cloudns_get_zone_name() { if ! _contains "$response" "\"status\":\"Failed\""; then echo $zoneForCheck - return 0; + return 0 fi i=$(expr $i + 1) done - return 1; + return 1 } -_dns_cloudns_get_record_id() { +_dns_cloudns_get_record_id () { _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" if _contains "$response" "\"id\":"; then echo $response | awk 'BEGIN { FS="\"" } {print $2}' @@ -154,5 +153,5 @@ _dns_cloudns_http_api_call () { _debug response "$response" - return 1; + return 1 } \ No newline at end of file From 0dd6377fe666ded6d0919acd6e8fb8adc0d497ea Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:25:50 +0200 Subject: [PATCH 257/620] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 39d8c3a6..1726b81a 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -7,7 +7,7 @@ CLOUDNS_API="https://api.cloudns.net" ######## Public functions ##################### #Usage: dns_cloudns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cloudns_add () { +dns_cloudns_add() { _info "Using cloudns" if ! _dns_cloudns_init_check; then @@ -20,8 +20,8 @@ dns_cloudns_add () { return 1 fi - host="$(echo $1 | sed "s/\.$zone\$//")" - record=$2 + host="$(echo "$1" | sed "s/\.$zone\$//")" + record=$2 record_id=$(_dns_cloudns_get_record_id "$zone" "$host") _debug zone "$zone" @@ -52,14 +52,14 @@ dns_cloudns_add () { } #Usage: dns_cloudns_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cloudns_rm () { +dns_cloudns_rm() { _info "Using cloudns" if ! _dns_cloudns_init_check; then - return 1 + return 1 fi - if [ -z $zone ]; then + if [ -z "$zone" ]; then zone="$(_dns_cloudns_get_zone_name $1)" if [ -z "$zone" ]; then _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." @@ -67,8 +67,8 @@ dns_cloudns_rm () { fi fi - host="$(echo $1|sed "s/\.$zone\$//")" - record=$2 + host="$(echo "$1" | sed "s/\.$zone\$//")" + record=$2 record_id=$(_dns_cloudns_get_record_id "$zone" "$host") _debug zone "$zone" @@ -89,8 +89,8 @@ dns_cloudns_rm () { } #################### Private functions below ################################## -_dns_cloudns_init_check () { - if [ ! -z $CLOUDNS_INIT_CHECK_COMPLETED ]; then +_dns_cloudns_init_check() { + if [ ! -z "$CLOUDNS_INIT_CHECK_COMPLETED" ]; then return 0 fi @@ -109,7 +109,7 @@ _dns_cloudns_init_check () { return 0 } -_dns_cloudns_get_zone_name () { +_dns_cloudns_get_zone_name() { i=2 while true; do zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) @@ -123,7 +123,7 @@ _dns_cloudns_get_zone_name () { _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" if ! _contains "$response" "\"status\":\"Failed\""; then - echo $zoneForCheck + echo "$zoneForCheck" return 0 fi @@ -132,16 +132,16 @@ _dns_cloudns_get_zone_name () { return 1 } -_dns_cloudns_get_record_id () { +_dns_cloudns_get_record_id() { _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" if _contains "$response" "\"id\":"; then - echo $response | awk 'BEGIN { FS="\"" } {print $2}' + echo "$response" | awk 'BEGIN { FS="\"" } {print $2}' return 0 fi return 1 } -_dns_cloudns_http_api_call () { +_dns_cloudns_http_api_call() { method=$1 _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" From a15f87ae39d33e0d35838e4dc5c810bd934fc232 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:26:57 +0200 Subject: [PATCH 258/620] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 1726b81a..3eb10b33 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -127,7 +127,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$(expr $i + 1) + i=$(expr "$i" + 1) done return 1 } From 5df2ca3ef301fe8bbcf0c7e11c5ef9a1c0484aca Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:38:02 +0200 Subject: [PATCH 259/620] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 3eb10b33..cd83619f 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -14,7 +14,7 @@ dns_cloudns_add() { return 1 fi - zone="$(_dns_cloudns_get_zone_name $1)" + zone="$(_dns_cloudns_get_zone_name "$1")" if [ -z "$zone" ]; then _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." return 1 @@ -28,7 +28,6 @@ dns_cloudns_add() { _debug host "$host" _debug record "$record" _debug record_id "$record_id" - if [ -z "$record_id" ]; then _info "Adding the TXT record for $1" @@ -60,7 +59,7 @@ dns_cloudns_rm() { fi if [ -z "$zone" ]; then - zone="$(_dns_cloudns_get_zone_name $1)" + zone="$(_dns_cloudns_get_zone_name "$1")" if [ -z "$zone" ]; then _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." return 1 @@ -118,7 +117,7 @@ _dns_cloudns_get_zone_name() { return 1 fi - _debug zoneForCheck $zoneForCheck + _debug zoneForCheck "$zoneForCheck" _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" @@ -127,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$(expr "$i" + 1) + i=$(($i+1)) done return 1 } From f881d6c44ff6f5043399ae3b379c158aa2ec69e8 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:40:18 +0200 Subject: [PATCH 260/620] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index cd83619f..698cc26e 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -153,4 +153,4 @@ _dns_cloudns_http_api_call() { _debug response "$response" return 1 -} \ No newline at end of file +} From 55a5da2102c2bfe9e41e2d32e7e29c7eb301e9ce Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:42:51 +0200 Subject: [PATCH 261/620] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 698cc26e..efa7ce7e 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -126,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$(($i+1)) + i=$(($i + 1)) done return 1 } From 3d8598654c82128ac8e6be44f9f6127f9c778f09 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 14:43:43 +0200 Subject: [PATCH 262/620] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index efa7ce7e..d12db033 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -126,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$(($i + 1)) + i=$((${i} + 1)) done return 1 } From ac11ba3d60534bc52478c6016e6025d4be8e93ad Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Tue, 14 Mar 2017 15:12:02 +0200 Subject: [PATCH 263/620] Add DNS API for ClouDNS --- dnsapi/dns_cloudns.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index d12db033..d000d6a2 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -28,7 +28,7 @@ dns_cloudns_add() { _debug host "$host" _debug record "$record" _debug record_id "$record_id" - + if [ -z "$record_id" ]; then _info "Adding the TXT record for $1" _dns_cloudns_http_api_call "dns/add-record.json" "domain-name=$zone&record-type=TXT&host=$host&record=$record&ttl=60" @@ -126,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$((${i} + 1)) + i=$((i + 1)) done return 1 } From be972fc0b5dc13171380fe0c88ac371539d45ef9 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 10:00:21 +0200 Subject: [PATCH 264/620] fixes for the comments in #723 --- dnsapi/dns_cloudns.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index d000d6a2..a9615c58 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -126,7 +126,7 @@ _dns_cloudns_get_zone_name() { return 0 fi - i=$((i + 1)) + i=$(_math "$i" + 1) done return 1 } @@ -150,7 +150,7 @@ _dns_cloudns_http_api_call() { response="$(_get "$CLOUDNS_API/$method?$data")" - _debug response "$response" + _debug2 response "$response" - return 1 + return 0 } From f063dd195e44c099c0c65322049745af5cbb063a Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 15:49:14 +0200 Subject: [PATCH 265/620] some additional fixes and removed awk --- dnsapi/dns_cloudns.sh | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index a9615c58..9f6f1679 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -77,7 +77,7 @@ dns_cloudns_rm() { if [ ! -z "$record_id" ]; then _info "Deleting the TXT record for $1" - _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=" + _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=$record_id" if ! _contains "$response" "\"status\":\"Success\""; then _err "The TXT record for $1 cannot be deleted." return 1 @@ -103,6 +103,13 @@ _dns_cloudns_init_check() { return 1 fi + _dns_cloudns_http_api_call "dns/login.json" "" + + if ! _contains "$response" "\"status\":\"Success\""; then + _err "Invalid CLOUDNS_AUTH_ID or CLOUDNS_AUTH_PASSWORD. Please check your login credentials." + return 1 + fi + CLOUDNS_INIT_CHECK_COMPLETED=1 return 0 @@ -134,7 +141,7 @@ _dns_cloudns_get_zone_name() { _dns_cloudns_get_record_id() { _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" if _contains "$response" "\"id\":"; then - echo "$response" | awk 'BEGIN { FS="\"" } {print $2}' + echo "$response" | cut -d '"' -f 2 return 0 fi return 1 @@ -146,7 +153,11 @@ _dns_cloudns_http_api_call() { _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" - data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" + if [ -z $2 ]; then + data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD" + else + data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" + fi response="$(_get "$CLOUDNS_API/$method?$data")" From 136d1b04b5379401ab721dc0939f9b0aa24507cb Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 15:52:05 +0200 Subject: [PATCH 266/620] some additional fixes and removed awk --- dnsapi/dns_cloudns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 9f6f1679..4bb2c267 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -153,7 +153,7 @@ _dns_cloudns_http_api_call() { _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" - if [ -z $2 ]; then + if [ -z "$2" ]; then data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD" else data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" From c0b20275885437ff540c747b4f936510215a74ce Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 15:58:04 +0200 Subject: [PATCH 267/620] add ClouDNS to the list in the main README file --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 52231d0f..1cf29746 100644 --- a/README.md +++ b/README.md @@ -309,6 +309,7 @@ You don't have to do anything manually! 1. Gandi LiveDNS API 1. Knot DNS API 1. DigitalOcean API (native) +1. ClouDNS API **More APIs coming soon...** From 819d2bc560e260e09a41b1124794f8348b899f2d Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 15 Mar 2017 22:52:57 +0800 Subject: [PATCH 268/620] fix for wget. fix https://github.com/Neilpang/acme.sh/issues/724#issuecomment-286761682 --- dnsapi/dns_aws.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 84aa28d3..d5d52de0 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -143,7 +143,7 @@ aws_rest() { CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n" SignedHeaders="host;x-amz-date" if [ -n "$AWS_SESSION_TOKEN" ]; then - export _H2="x-amz-security-token: $AWS_SESSION_TOKEN" + export _H3="x-amz-security-token: $AWS_SESSION_TOKEN" CanonicalHeaders="${CanonicalHeaders}x-amz-security-token:$AWS_SESSION_TOKEN\n" SignedHeaders="${SignedHeaders};x-amz-security-token" fi @@ -204,8 +204,8 @@ aws_rest() { Authorization="$Algorithm Credential=$AWS_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature" _debug2 Authorization "$Authorization" - _H3="Authorization: $Authorization" - _debug _H3 "$_H3" + _H2="Authorization: $Authorization" + _debug _H2 "$_H2" url="$AWS_URL/$ep" From 5ffca2d1383c017f07897dd8c77c34beb15153c2 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 17:16:54 +0200 Subject: [PATCH 269/620] Update cotnact details --- dnsapi/dns_cloudns.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 4bb2c267..f48a8052 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -1,5 +1,8 @@ #!/usr/bin/env sh +# Author: Boyan Peychev +# Repository: https://github.com/ClouDNS/acme.sh/ + #CLOUDNS_AUTH_ID=XXXXX #CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" CLOUDNS_API="https://api.cloudns.net" From 3e9478b58dda04923a2c1eeae9ad9613a04cc079 Mon Sep 17 00:00:00 2001 From: boyanpeychev Date: Wed, 15 Mar 2017 17:25:01 +0200 Subject: [PATCH 270/620] Update README information for ClouDNS --- README.md | 2 +- dnsapi/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1cf29746..5c1ddd80 100644 --- a/README.md +++ b/README.md @@ -309,7 +309,7 @@ You don't have to do anything manually! 1. Gandi LiveDNS API 1. Knot DNS API 1. DigitalOcean API (native) -1. ClouDNS API +1. ClouDNS.net API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 702efc1c..d419d5ed 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -407,7 +407,7 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_dgon -d example.com -d www.example.com ``` -## 21. Use ClouDNS API +## 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/ From 7044236824af45431413297c6224e11dcc785733 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Wed, 15 Mar 2017 11:40:32 -0700 Subject: [PATCH 271/620] Create dns_dynu.sh Add DNS API support for Dynu. --- dnsapi/dns_dynu.sh | 135 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 dnsapi/dns_dynu.sh diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh new file mode 100644 index 00000000..963bdd2f --- /dev/null +++ b/dnsapi/dns_dynu.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env sh + +my_dir="$(dirname "$0")" +source "$my_dir/acme.sh" + +#Client ID +Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d" +# +#Secret +Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9" +# +#Token +Dynu_Token="" +# +#Endpoint +Dynu_EndPoint="https://api.dynu.com/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_dynu_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$Dynu_ClientId" ] || [ -z "$Dynu_Secret" ]; then + Dynu_ClientId="" + Dynu_Secret="" + _err "Dynu client id and secret is not specified." + _err "Please create you API client id and secret and try again." + return 1 + fi + + #save the client id and secret to the account conf file. + _saveaccountconf Dynu_ClientId "$Dynu_ClientId" + _saveaccountconf Dynu_Secret "$Dynu_Secret" + + if [ -z "$Dynu_Token" ]; then + _info "Getting Dynu token" + if ! _dynu_authentication; then + _err "Can not get token." + fi + fi + + _debug "Detect root zone" + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + + _debug _node "$_node" + _debug _domain_name "$_domain_name" + + _info "Creating TXT record" + if ! _dynu_rest POST "dns/record/add" "{\"domain_name\":\"$_domain_name\",\"node_name\":\"$_node\",\"record_type\":\"TXT\",\"text_data\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then + return 1 + fi + + if ! _contains "$response" "text_data"; then + _err "Could not add TXT record" + return 1 + fi + + return 0 +} + +#fulldomain +dns_dynu_rm() { + fulldomain=$1 +} + +######## Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _node=_acme-challenge.www +# _domain_name=domain.com +_get_root() { + domain=$1 + if ! _dynu_rest GET "dns/getroot/$domain"; then + return 1 + fi + + if ! _contains "$response" "domain_name"; then + _debug "Domain name not found" + return 1 + fi + + _domain_name=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 1 | cut -d : -f 2 | cut -d '"' -f 2) + _node=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 3 | cut -d : -f 2 | cut -d '"' -f 2) + return 0 +} + +_dynu_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Authorization: Bearer $Dynu_Token" + export _H2="Content-Type: application/json" + + if [ "$data" ]; then + _debug data "$data" + response="$(_post "$data" "$Dynu_EndPoint/$ep" "" "$m")" + else + echo "Getting $Dynu_EndPoint/$ep" + response="$(_get "$Dynu_EndPoint/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + +_dynu_authentication() { + export _H1="Authorization: Basic $(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" + export _H2="Content-Type: application/json" + + response="$(_get "$Dynu_EndPoint/oauth2/token")" + if [ "$?" != "0" ]; then + _err "Authentication failed." + return 1 + fi + if _contains "$response" "accessToken"; then + Dynu_Token=$(printf "%s" "$response" | tr -d "[]" | cut -d , -f 2 | cut -d : -f 2 | cut -d '"' -f 2) + fi + if _contains "$Dynu_Token" "null"; then + Dynu_Token="" + fi + + _debug2 response "$response" + return 0 +} From c87cd0de73f263ad2ce9892213a912b3ad691d07 Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 16 Mar 2017 18:02:36 +0800 Subject: [PATCH 272/620] fix https://github.com/Neilpang/acme.sh/issues/729 https://github.com/Neilpang/acme.sh/issues/721 --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 7906aa4c..671b0d33 100755 --- a/acme.sh +++ b/acme.sh @@ -3477,7 +3477,10 @@ issue() { if [ ! "$usingApache" ]; then if webroot_owner=$(_stat "$_currentRoot"); then _debug "Changing owner/group of .well-known to $webroot_owner" - chown -R "$webroot_owner" "$_currentRoot/.well-known" + if ! _exec "chown -R \"$webroot_owner\" \"$_currentRoot/.well-known\""; then + _debug "$(cat "$_EXEC_TEMP_ERR")" + _exec_err >/dev/null 2>&1 + fi else _debug "not chaning owner/group of webroot" fi From 5c78e0a462178ea5424b241b486252c331c2bd53 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Thu, 16 Mar 2017 13:42:30 -0700 Subject: [PATCH 273/620] removed source acme.sh --- dnsapi/dns_dynu.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 963bdd2f..b12b0bbb 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -1,8 +1,5 @@ #!/usr/bin/env sh -my_dir="$(dirname "$0")" -source "$my_dir/acme.sh" - #Client ID Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d" # From 2aa75f034ff1730bc576737b28b8002c7100129b Mon Sep 17 00:00:00 2001 From: jtbr Date: Sun, 19 Mar 2017 16:10:09 +0100 Subject: [PATCH 274/620] Adds support for --ca-path option for using non-default curl/wget CA certs --- acme.sh | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 671b0d33..68a3799a 100755 --- a/acme.sh +++ b/acme.sh @@ -1479,7 +1479,9 @@ _inithttp() { _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP " fi - if [ "$CA_BUNDLE" ]; then + if [ "$CA_PATH" ]; then + _ACME_CURL="$_ACME_CURL --capath $CA_PATH " + elif [ "$CA_BUNDLE" ]; then _ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE " fi @@ -1490,8 +1492,10 @@ _inithttp() { if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then _ACME_WGET="$_ACME_WGET -d " fi - if [ "$CA_BUNDLE" ]; then - _ACME_WGET="$_ACME_WGET --ca-certificate $CA_BUNDLE " + if [ "$CA_PATH" ]; then + _ACME_WGET="$_ACME_WGET --ca-directory=$CA_PATH " + elif [ "$CA_BUNDLE" ]; then + _ACME_WGET="$_ACME_WGET --ca-certificate=$CA_BUNDLE " fi fi @@ -3702,6 +3706,12 @@ issue() { else _clearaccountconf "CA_BUNDLE" fi + + if [ "$CA_PATH" ]; then + _saveaccountconf CA_PATH "$CA_PATH" + else + _clearaccountconf "CA_PATH" + fi if [ "$HTTPS_INSECURE" ]; then _saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE" @@ -4918,6 +4928,7 @@ _process() { _stopRenewOnError="" #_insecure="" _ca_bundle="" + _ca_path="" _nocron="" _ecc="" _csr="" @@ -5232,6 +5243,11 @@ _process() { CA_BUNDLE="$_ca_bundle" shift ;; + --ca-path) + _ca_path="$2" + CA_PATH="$_ca_path" + shift + ;; --nocron) _nocron="1" ;; From f21dd9117dc470f47668439ede249916d0a8cd2c Mon Sep 17 00:00:00 2001 From: jtbr Date: Sun, 19 Mar 2017 17:55:26 +0100 Subject: [PATCH 275/620] Handle case of busybox netstat, with no pid support --- acme.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 671b0d33..d5d9f313 100755 --- a/acme.sh +++ b/acme.sh @@ -1131,8 +1131,12 @@ _ss() { elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then #for solaris netstat -an -P tcp | grep "\.$_port " | grep "LISTEN" - else + elif netstat -help 2>&1 | grep "\-p" > /dev/null; then + #for full linux netstat -ntpl | grep ":$_port " + else + #for busybox (embedded linux; no pid support) + netstat -ntl 2>/dev/null | grep ":$_port " fi fi return 0 From f19f21007c081074a47baba06582d53acfd8586a Mon Sep 17 00:00:00 2001 From: jtbr Date: Mon, 20 Mar 2017 18:51:45 +0100 Subject: [PATCH 276/620] formatting --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d5d9f313..043308e9 100755 --- a/acme.sh +++ b/acme.sh @@ -1131,7 +1131,7 @@ _ss() { elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then #for solaris netstat -an -P tcp | grep "\.$_port " | grep "LISTEN" - elif netstat -help 2>&1 | grep "\-p" > /dev/null; then + elif netstat -help 2>&1 | grep "\-p" >/dev/null; then #for full linux netstat -ntpl | grep ":$_port " else From 4bdab73dd51f9bad4c823ab199b5c85ff0808fe4 Mon Sep 17 00:00:00 2001 From: jtbr Date: Mon, 20 Mar 2017 18:53:08 +0100 Subject: [PATCH 277/620] formatting --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 68a3799a..67b52cfe 100755 --- a/acme.sh +++ b/acme.sh @@ -3706,7 +3706,7 @@ issue() { else _clearaccountconf "CA_BUNDLE" fi - + if [ "$CA_PATH" ]; then _saveaccountconf CA_PATH "$CA_PATH" else From 5c539af7d7645723b928389bc93da526f0dcfa60 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 22 Mar 2017 21:20:35 +0800 Subject: [PATCH 278/620] rename parameters --- README.md | 10 +++++----- acme.sh | 38 +++++++++++++++++++------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 5c1ddd80..64609067 100644 --- a/README.md +++ b/README.md @@ -161,17 +161,17 @@ You **MUST** use this command to copy the certs to the target files, **DO NOT** **Apache** example: ```bash acme.sh --install-cert -d example.com \ ---certpath /path/to/certfile/in/apache/cert.pem \ ---keypath /path/to/keyfile/in/apache/key.pem \ ---fullchainpath /path/to/fullchain/certfile/apache/fullchain.pem \ +--cert-file /path/to/certfile/in/apache/cert.pem \ +--key-file /path/to/keyfile/in/apache/key.pem \ +--fullchain-file /path/to/fullchain/certfile/apache/fullchain.pem \ --reloadcmd "service apache2 force-reload" ``` **Nginx** example: ```bash acme.sh --install-cert -d example.com \ ---keypath /path/to/keyfile/in/nginx/key.pem \ ---fullchainpath /path/to/fullchain/nginx/cert.pem \ +--key-file /path/to/keyfile/in/nginx/key.pem \ +--fullchain-file /path/to/fullchain/nginx/cert.pem \ --reloadcmd "service nginx force-reload" ``` diff --git a/acme.sh b/acme.sh index f8a1c49d..15257687 100755 --- a/acme.sh +++ b/acme.sh @@ -4035,7 +4035,7 @@ deploy() { installcert() { _main_domain="$1" if [ -z "$_main_domain" ]; then - _usage "Usage: $PROJECT_ENTRY --installcert -d domain.com [--ecc] [--certpath cert-file-path] [--keypath key-file-path] [--capath ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]" + _usage "Usage: $PROJECT_ENTRY --installcert -d domain.com [--ecc] [--cert-file cert-file-path] [--key-file key-file-path] [--ca-file ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchain-file fullchain-path]" return 1 fi @@ -4785,10 +4785,10 @@ Parameters: These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: - --certpath /path/to/real/cert/file After issue/renew, the cert will be copied to this path. - --keypath /path/to/real/key/file After issue/renew, the key will be copied to this path. - --capath /path/to/real/ca/file After issue/renew, the intermediate cert will be copied to this path. - --fullchainpath /path/to/fullchain/file After issue/renew, the fullchain cert will be copied to this path. + --cert-file /path/to/real/cert/file After issue/renew, the cert will be copied to this path. + --key-file /path/to/real/key/file After issue/renew, the key will be copied to this path. + --ca-file /path/to/real/ca/file After issue/renew, the intermediate cert will be copied to this path. + --fullchain-file /path/to/fullchain/file After issue/renew, the fullchain cert will be copied to this path. --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. @@ -4913,10 +4913,10 @@ _process() { _webroot="" _keylength="" _accountkeylength="" - _certpath="" - _keypath="" - _capath="" - _fullchainpath="" + _cert_file="" + _key_file="" + _ca_file="" + _fullchain_file="" _reloadcmd="" _password="" _accountconf="" @@ -5158,20 +5158,20 @@ _process() { shift ;; - --certpath) - _certpath="$2" + --cert-file | --certpath) + _cert_file="$2" shift ;; - --keypath) - _keypath="$2" + --key-file | --keypath) + _key_file="$2" shift ;; - --capath) - _capath="$2" + --ca-file | --capath) + _ca_file="$2" shift ;; - --fullchainpath) - _fullchainpath="$2" + --fullchain-file | --fullchainpath) + _fullchain_file="$2" shift ;; --reloadcmd | --reloadCmd) @@ -5393,7 +5393,7 @@ _process() { uninstall) uninstall "$_nocron" ;; upgrade) upgrade ;; issue) - issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" + issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" ;; deploy) deploy "$_domain" "$_deploy_hook" "$_ecc" @@ -5405,7 +5405,7 @@ _process() { showcsr "$_csr" "$_domain" ;; installcert) - installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_ecc" + installcert "$_domain" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_ecc" ;; renew) renew "$_domain" "$_ecc" From 13fe54c938e964caefe74a9bb46087b6fbc4121f Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 22 Mar 2017 22:58:03 +0800 Subject: [PATCH 279/620] update doc --- acme.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 15257687..244f72e3 100755 --- a/acme.sh +++ b/acme.sh @@ -4785,10 +4785,10 @@ Parameters: These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert: - --cert-file /path/to/real/cert/file After issue/renew, the cert will be copied to this path. - --key-file /path/to/real/key/file After issue/renew, the key will be copied to this path. - --ca-file /path/to/real/ca/file After issue/renew, the intermediate cert will be copied to this path. - --fullchain-file /path/to/fullchain/file After issue/renew, the fullchain cert will be copied to this path. + --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. + --ca-file After issue/renew, the intermediate cert will be copied to this path. + --fullchain-file After issue/renew, the fullchain cert will be copied to this path. --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. @@ -4807,6 +4807,7 @@ Parameters: --stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal. --insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted. --ca-bundle Specifices 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. --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' --csr Specifies the input csr. From 4ddafb8e84cc2c647f788a58f0ba148433dfa7e3 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:14:28 -0500 Subject: [PATCH 280/620] Added Infoblox reference --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 64609067..014f0db3 100644 --- a/README.md +++ b/README.md @@ -310,6 +310,7 @@ You don't have to do anything manually! 1. Knot DNS API 1. DigitalOcean API (native) 1. ClouDNS.net API +1. Infoblox NIOS API (https://www.infoblox.com/) **More APIs coming soon...** From d03929507058c13ce81a925a77b2320fcb9bb147 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:15:17 -0500 Subject: [PATCH 281/620] Added Infoblox references --- dnsapi/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index d419d5ed..4543d9b4 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -421,6 +421,23 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com ``` +## 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. + # Use custom API If your API is not supported yet, you can write your own DNS API. From b0561058c6a19e700d19ec9233d8d656f7cbed46 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:16:31 -0500 Subject: [PATCH 282/620] Infoblox API --- dnsapi/dns_infoblox.sh | 93 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 dnsapi/dns_infoblox.sh diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh new file mode 100644 index 00000000..e71c90c9 --- /dev/null +++ b/dnsapi/dns_infoblox.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env sh + +dns_infoblox_add() { + + ## Nothing to see here, just some housekeeping + fulldomain=$1 + txtvalue=$2 + baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue" + + _info "Using Infoblox API" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ## Check for the credentials + if [ -z "$Infoblox_Creds" ] || [ -z "$Infoblox_Server" ]; then + Infoblox_Creds="" + Infoblox_Server="" + _err "You didn't specify the credentials or server yet (Infoblox_Creds and Infoblox_Server)." + _err "Please set them via EXPORT ([username:password] and [ip or hostname]) and try again." + return 1 + fi + + ## Save the credentials to the account file + _saveaccountconf Infoblox_Creds "$Infoblox_Creds" + _saveaccountconf Infoblox_Server "$Infoblox_Server" + + ## Base64 encode the credentials + Infoblox_CredsEncoded=$(printf "$Infoblox_Creds" | _base64) + + ## Construct the HTTP Authorization header + export _H1="Accept-Language:en-US" + export _H2="Authorization: Basic $Infoblox_CredsEncoded" + + ## Add the challenge record to the Infoblox grid member + result=$(_post "" "$baseurlnObject" "" "POST") + + ## Let's see if we get something intelligible back from the unit + if echo "$result" | egrep 'record:txt/.*:.*/default'; then + _info "Successfully created the txt record" + return 0 + else + _err "Error encountered during record addition" + _err "$result" + return 1 + fi + +} + +dns_infoblox_rm() { + + ## Nothing to see here, just some housekeeping + fulldomain=$1 + txtvalue=$2 + + _info "Using Infoblox API" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ## Base64 encode the credentials + Infoblox_CredsEncoded=$(printf "$Infoblox_Creds" | _base64) + + ## Construct the HTTP Authorization header + export _H1="Accept-Language:en-US" + export _H2="Authorization: Basic $Infoblox_CredsEncoded" + + ## Does the record exist? Let's check. + baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&_return_type=xml-pretty" + result=$(_get "$baseurlnObject") + + ## Let's see if we get something intelligible back from the grid + if echo "$result" | egrep 'record:txt/.*:.*/default'; then + ## Extract the object reference + objRef=$(_egrep_o 'record:txt/.*:.*/default' <<<$result) + objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" + ## Delete them! All the stale records! + rmResult=$(_post "" "$objRmUrl" "" "DELETE") + ## Let's see if that worked + if echo "$rmResult" | egrep 'record:txt/.*:.*/default'; then + _info "Successfully deleted $objRef" + return 0 + else + _err "Error occurred during txt record delete" + _err "$rmResult" + return 1 + fi + else + _err "Record to delete didn't match an existing record" + _err "$result" + return 1 + fi +} + +#################### Private functions below ################################## From b1e4a7c61570137cf04901f3f92e3f4c8449b023 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:34:29 -0500 Subject: [PATCH 283/620] Fixed (hopefully) TravisCI errors --- dnsapi/dns_infoblox.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index e71c90c9..347c69e7 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -25,7 +25,7 @@ dns_infoblox_add() { _saveaccountconf Infoblox_Server "$Infoblox_Server" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(printf "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded=$(echo -n "$Infoblox_Creds" | _base64) ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -57,7 +57,7 @@ dns_infoblox_rm() { _debug txtvalue "$txtvalue" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(printf "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded=$(echo -n "$Infoblox_Creds" | _base64) ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -70,7 +70,7 @@ dns_infoblox_rm() { ## Let's see if we get something intelligible back from the grid if echo "$result" | egrep 'record:txt/.*:.*/default'; then ## Extract the object reference - objRef=$(_egrep_o 'record:txt/.*:.*/default' <<<$result) + objRef=$(_egrep_o 'record:txt/.*:.*/default' <<< $result) objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" ## Delete them! All the stale records! rmResult=$(_post "" "$objRmUrl" "" "DELETE") From 2c37d946111034eacf23b20a38a511ab131b2f3c Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 14:40:09 -0500 Subject: [PATCH 284/620] More bs --- dnsapi/dns_infoblox.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 347c69e7..975dc771 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -70,7 +70,7 @@ dns_infoblox_rm() { ## Let's see if we get something intelligible back from the grid if echo "$result" | egrep 'record:txt/.*:.*/default'; then ## Extract the object reference - objRef=$(_egrep_o 'record:txt/.*:.*/default' <<< $result) + objRef=$(_egrep_o 'record:txt/.*:.*/default' <<<$result) objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" ## Delete them! All the stale records! rmResult=$(_post "" "$objRmUrl" "" "DELETE") From 7dc548b4b8764f8d8f36898a9f19db1ba2adb92e Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 15:06:37 -0500 Subject: [PATCH 285/620] MORE bs --- dnsapi/dns_infoblox.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 975dc771..8b9f9370 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -25,7 +25,7 @@ dns_infoblox_add() { _saveaccountconf Infoblox_Server "$Infoblox_Server" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(echo -n "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -57,7 +57,7 @@ dns_infoblox_rm() { _debug txtvalue "$txtvalue" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(echo -n "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -70,7 +70,7 @@ dns_infoblox_rm() { ## Let's see if we get something intelligible back from the grid if echo "$result" | egrep 'record:txt/.*:.*/default'; then ## Extract the object reference - objRef=$(_egrep_o 'record:txt/.*:.*/default' <<<$result) + objRef=$(printf "%b" "$result" | _egrep_o 'record:txt/.*:.*/default') objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" ## Delete them! All the stale records! rmResult=$(_post "" "$objRmUrl" "" "DELETE") From 1424e8a2de3f43947045a4861f3c3f9634d19748 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 23 Mar 2017 20:20:04 -0500 Subject: [PATCH 286/620] Added attribution --- dnsapi/dns_infoblox.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 8b9f9370..3846e62e 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -1,5 +1,9 @@ #!/usr/bin/env sh +## Infoblox API integration by Jason Keller and Elijah Tenai +## +## Report any bugs via https://github.com/jasonkeller/acme.sh + dns_infoblox_add() { ## Nothing to see here, just some housekeeping From 8afd31902fdff51ee3ce66fe124892d8cb232b3e Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:24:26 +0000 Subject: [PATCH 287/620] spelling: application --- 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 faf5b42b..71642bd4 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -#Applcation Key +#Application Key #OVH_AK="sdfsdfsdfljlbjkljlkjsdfoiwje" # #Application Secret From 3d22708f670ebcf56325631d25ca3e769f9cf8ef Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:24:38 +0000 Subject: [PATCH 288/620] spelling: automatically --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 4543d9b4..9eb77915 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -302,7 +302,7 @@ acme.sh --issue --dns dns_freedns -d example.com -d www.example.com ``` Note that you cannot use acme.sh automatic DNS validation for FreeDNS public domains or for a subdomain that -you create under a FreeDNS public domain. You must own the top level domain in order to automaitcally +you create under a FreeDNS public domain. You must own the top level domain in order to automatically validate with acme.sh at FreeDNS. ## 16. Use cyon.ch From bcbecff6f6d4fed138a63255ae344bb70610d907 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:24:52 +0000 Subject: [PATCH 289/620] spelling: certificate --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 014f0db3..7a79bed4 100644 --- a/README.md +++ b/README.md @@ -329,7 +329,7 @@ Just set the `length` parameter with a prefix `ec-`. For example: -### Single domain ECC cerfiticate +### Single domain ECC certificate ```bash acme.sh --issue -w /home/wwwroot/example.com -d example.com --keylength ec-256 From 291c97dc81aeabacd40f14eda71d98bfa3f7a112 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:25:04 +0000 Subject: [PATCH 290/620] spelling: challenge --- 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 f30c8958..14622ad1 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -112,7 +112,7 @@ dns_freedns_add() { # not produce accurate results as the value field is truncated # on this webpage. To get full value we would need to load # another page. However we don't really need this so long as - # there is only one TXT record for the acme chalenge subdomain. + # there is only one TXT record for the acme challenge subdomain. DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')" if [ $found != 0 ]; then break From 9b2aa974ba57d9953a18ee218468c253770a34a0 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:25:31 +0000 Subject: [PATCH 291/620] spelling: changed --- 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 14622ad1..7c1f009e 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -65,7 +65,7 @@ dns_freedns_add() { htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" if [ "$?" != "0" ]; then if [ "$using_cached_cookies" = "true" ]; then - _err "Has your FreeDNS username and password channged? If so..." + _err "Has your FreeDNS username and password changed? If so..." _err "Please export as FREEDNS_User / FREEDNS_Password and try again." fi return 1 From b54ce3107897f60d784da78c29c8e2faf75df703 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:25:23 +0000 Subject: [PATCH 292/620] spelling: changing --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 244f72e3..bbefb6bc 100755 --- a/acme.sh +++ b/acme.sh @@ -3490,7 +3490,7 @@ issue() { _exec_err >/dev/null 2>&1 fi else - _debug "not chaning owner/group of webroot" + _debug "not changing owner/group of webroot" fi fi From 4cedbf80df52aeb39489caeb4646a9625f17ea8a Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:26:20 +0000 Subject: [PATCH 293/620] spelling: delimiter --- deploy/kong.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 3b9c5c79..80a4b02d 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -43,7 +43,7 @@ kong_deploy() { #Save kong url if it's succesful (First run case) _saveaccountconf KONG_URL "$KONG_URL" #Generate DEIM - delim="-----MultipartDelimeter$(date "+%s%N")" + delim="-----MultipartDelimiter$(date "+%s%N")" nl="\015\012" #Set Header _H1="Content-Type: multipart/form-data; boundary=$delim" From 506f36b26ddc0dae35a5bf11316ae0fbe53c4fda Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:26:43 +0000 Subject: [PATCH 294/620] spelling: embedded --- dnsapi/dns_pdns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_pdns.sh b/dnsapi/dns_pdns.sh index ebc02949..7d807c81 100755 --- a/dnsapi/dns_pdns.sh +++ b/dnsapi/dns_pdns.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -#PowerDNS Emdedded API +#PowerDNS Embedded API #https://doc.powerdns.com/md/httpapi/api_spec/ # #PDNS_Url="http://ns.example.com:8081" From 39f3239682b98a9ac9a83a646110dd24f7aba728 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:26:55 +0000 Subject: [PATCH 295/620] spelling: following --- 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 7c1f009e..6383c589 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -10,7 +10,7 @@ # ######## Public functions ##################### -# Export FreeDNS userid and password in folowing variables... +# Export FreeDNS userid and password in following variables... # FREEDNS_User=username # FREEDNS_Password=password # login cookie is saved in acme account config file so userid / pw From d39b1082746f3b7672dfe34311704163ffbe62f1 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:27:04 +0000 Subject: [PATCH 296/620] spelling: function --- 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 6383c589..aebbc68c 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -192,7 +192,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() fuction + # acme.sh does not have a _readaccountconf() function FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")" _debug "FreeDNS login cookies: $FREEDNS_COOKIE" From 357b514bc903e2e2c8acf500f760a8c7027df3ec Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:28:04 +0000 Subject: [PATCH 297/620] spelling: lines --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index bbefb6bc..22cd412c 100755 --- a/acme.sh +++ b/acme.sh @@ -879,7 +879,7 @@ _sign() { if ! _signedECText="$($_sign_openssl | $ACME_OPENSSL_BIN asn1parse -inform DER)"; then _err "Sign failed: $_sign_openssl" _err "Key file: $keyfile" - _err "Key content:$(wc -l <"$keyfile") lises" + _err "Key content:$(wc -l <"$keyfile") lines" return 1 fi _debug3 "_signedECText" "$_signedECText" From 84a6730b1a05edd91f74cd96ad902c88b8e373b7 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:28:37 +0000 Subject: [PATCH 298/620] spelling: obtain --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 22cd412c..d686834a 100755 --- a/acme.sh +++ b/acme.sh @@ -4812,7 +4812,7 @@ Parameters: --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' --csr Specifies the input csr. --pre-hook Command to be run before obtaining any certificates. - --post-hook Command to be run after attempting to obtain/renew certificates. No matter the obain/renew is success or failed. + --post-hook Command to be run after attempting to obtain/renew certificates. No matter the obtain/renew is success or failed. --renew-hook Command to be run once for each successfully renewed certificate. --deploy-hook The hook file to deploy cert --ocsp-must-staple, --ocsp Generate ocsp must Staple extension. From 00b34eb2a4adafde6dd338ceb03bc551b3519f73 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:28:57 +0000 Subject: [PATCH 299/620] spelling: occurred --- deploy/kong.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 80a4b02d..e1873f35 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -72,7 +72,7 @@ kong_deploy() { response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH") fi if ! [ "$(echo "$response" | _egrep_o "ssl")" = "ssl" ]; then - _err "An error occured with cert upload. Check response:" + _err "An error occurred with cert upload. Check response:" _err "$response" return 1 fi From df14085ec8ab262020c35d235d29c8aeda4e5af5 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:29:11 +0000 Subject: [PATCH 300/620] spelling: oops --- deploy/exim4.sh | 4 ++-- deploy/vsftpd.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/exim4.sh b/deploy/exim4.sh index bf92b438..573f762b 100644 --- a/deploy/exim4.sh +++ b/deploy/exim4.sh @@ -79,7 +79,7 @@ exim4_deploy() { _info "Restore conf success" eval "$_reload" else - _err "Opps, error restore exim4 conf, please report bug to us." + _err "Oops, error restore exim4 conf, please report bug to us." fi return 1 fi @@ -105,7 +105,7 @@ exim4_deploy() { _info "Restore conf success" eval "$_reload" else - _err "Opps, error restore exim4 conf, please report bug to us." + _err "Oops, error restore exim4 conf, please report bug to us." fi return 1 fi diff --git a/deploy/vsftpd.sh b/deploy/vsftpd.sh index 1c6410a6..ed44e709 100644 --- a/deploy/vsftpd.sh +++ b/deploy/vsftpd.sh @@ -76,7 +76,7 @@ vsftpd_deploy() { _info "Restore conf success" eval "$_reload" else - _err "Opps, error restore vsftpd conf, please report bug to us." + _err "Oops, error restore vsftpd conf, please report bug to us." fi return 1 fi @@ -102,7 +102,7 @@ vsftpd_deploy() { _info "Restore conf success" eval "$_reload" else - _err "Opps, error restore vsftpd conf, please report bug to us." + _err "Oops, error restore vsftpd conf, please report bug to us." fi return 1 fi From 61a48a5b9f775c1f7eaa56aefcb116881f458b85 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:29:30 +0000 Subject: [PATCH 301/620] spelling: please --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d686834a..91919e76 100755 --- a/acme.sh +++ b/acme.sh @@ -2385,7 +2385,7 @@ _setApache() { _debug "Backup apache config file" "$httpdconf" if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/"; then _err "Can not backup apache config file, so abort. Don't worry, the apache config is not changed." - _err "This might be a bug of $PROJECT_NAME , pleae report issue: $PROJECT" + _err "This might be a bug of $PROJECT_NAME , please report issue: $PROJECT" return 1 fi _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" From 849bed4bef08cbf303f7a97129bea804424af3da Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:03 +0000 Subject: [PATCH 302/620] spelling: requires --- 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 9ceede44..7e1f1fec 100755 --- a/dnsapi/dns_dgon.sh +++ b/dnsapi/dns_dgon.sh @@ -158,7 +158,7 @@ _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 requres manual requests with DO) + ## havent seen this request paginated, tested with 18 domains (more requires manual requests with DO) DOMURL="https://api.digitalocean.com/v2/domains" ## get the domain list (DO gives basically a full XFER!) From 997c517ba270727c7fa220e67a8680245c7b1b48 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:15 +0000 Subject: [PATCH 303/620] spelling: return --- 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 aebbc68c..6c8f95a9 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -53,7 +53,7 @@ dns_freedns_add() { i="$(_math "$i" - 1)" sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" - # Sometimes FreeDNS does not reurn the subdomain page but rather + # 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 @@ -196,7 +196,7 @@ dns_freedns_rm() { FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")" _debug "FreeDNS login cookies: $FREEDNS_COOKIE" - # Sometimes FreeDNS does not reurn the subdomain page but rather + # 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 From 0d6ce9f97773fce4ed811e7bfe2993fde48b739f Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:26 +0000 Subject: [PATCH 304/620] spelling: satisfy --- dnsapi/dns_cyon.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index c096d8b0..d7ad712c 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -50,7 +50,7 @@ _cyon_load_credentials() { fi if [ -z "${CY_Username}" ] || [ -z "${CY_Password}" ]; then - # Dummy entries to satify script checker. + # Dummy entries to satisfy script checker. CY_Username="" CY_Password="" CY_OTP_Secret="" From 00777a10ae38de2b3d59c94be3f9ebed098a9cd4 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:43 +0000 Subject: [PATCH 305/620] spelling: security --- 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 6c8f95a9..77e4322c 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -341,7 +341,7 @@ _freedns_add_txt_record() { return 1 elif _contains "$htmlpage" "security code was incorrect"; then _debug "$htmlpage" - _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested seurity code" + _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested security code" _err "Note that you cannot use automatic DNS validation for FreeDNS public domains" return 1 fi From f3c984281c927cf37cb61a556670ffb36dd0e7a0 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:30:58 +0000 Subject: [PATCH 306/620] spelling: specified --- dnsapi/dns_gandi_livedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 41f42980..28b8f99d 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -19,7 +19,7 @@ dns_gandi_livedns_add() { txtvalue=$2 if [ -z "$GANDI_LIVEDNS_KEY" ]; then - _err "No API key specifed for Gandi LiveDNS." + _err "No API key specified for Gandi LiveDNS." _err "Create your key and export it as GANDI_LIVEDNS_KEY" return 1 fi From 8f73e241755a3ad419245e705bcbb597e9d33c3e Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:31:12 +0000 Subject: [PATCH 307/620] spelling: specifies --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 91919e76..28c0721f 100755 --- a/acme.sh +++ b/acme.sh @@ -4806,7 +4806,7 @@ Parameters: --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. --insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted. - --ca-bundle Specifices the path to the CA certificate bundle to verify api server's certificate. + --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. --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' From 7f32488b781b5b1910839839606c71a5e3a6f69e Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:31:35 +0000 Subject: [PATCH 308/620] spelling: subdomain --- 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 77e4322c..272a1243 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -302,12 +302,12 @@ _freedns_retrieve_subdomain_page() { export _H2="Accept-Language:en-US" url="https://freedns.afraid.org/subdomain/" - _debug "Retrieve subdmoain page from FreeDNS" + _debug "Retrieve subdomain page from FreeDNS" htmlpage="$(_get "$url")" if [ "$?" != "0" ]; then - _err "FreeDNS retrieve subdomins failed bad RC from _get" + _err "FreeDNS retrieve subdomains failed bad RC from _get" return 1 elif [ -z "$htmlpage" ]; then _err "FreeDNS returned empty subdomain page" From f94433e504c7787b93751755f3347455c61dc629 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 Mar 2017 05:32:29 +0000 Subject: [PATCH 309/620] spelling: validation --- acme.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/acme.sh b/acme.sh index 28c0721f..ce5b1dbd 100755 --- a/acme.sh +++ b/acme.sh @@ -2258,16 +2258,16 @@ _initpath() { fi if [ -z "$TLS_CONF" ]; then - TLS_CONF="$DOMAIN_PATH/tls.valdation.conf" + TLS_CONF="$DOMAIN_PATH/tls.validation.conf" fi if [ -z "$TLS_CERT" ]; then - TLS_CERT="$DOMAIN_PATH/tls.valdation.cert" + TLS_CERT="$DOMAIN_PATH/tls.validation.cert" fi if [ -z "$TLS_KEY" ]; then - TLS_KEY="$DOMAIN_PATH/tls.valdation.key" + TLS_KEY="$DOMAIN_PATH/tls.validation.key" fi if [ -z "$TLS_CSR" ]; then - TLS_CSR="$DOMAIN_PATH/tls.valdation.csr" + TLS_CSR="$DOMAIN_PATH/tls.validation.csr" fi } @@ -2883,7 +2883,7 @@ _on_issue_err() { uri=$(echo "$ventry" | cut -d "$sep" -f 3) vtype=$(echo "$ventry" | cut -d "$sep" -f 4) _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) - __trigger_validaton "$uri" "$keyauthorization" + __trigger_validation "$uri" "$keyauthorization" done ) fi @@ -3105,7 +3105,7 @@ __get_domain_new_authz() { } #uri keyAuthorization -__trigger_validaton() { +__trigger_validation() { _debug2 "tigger domain validation." _t_url="$1" _debug2 _t_url "$_t_url" @@ -3531,7 +3531,7 @@ issue() { fi fi - if ! __trigger_validaton "$uri" "$keyauthorization"; then + if ! __trigger_validation "$uri" "$keyauthorization"; then _err "$d:Can not get challenge: $response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup From d0300d4443caf45f0619cba436b40128e09dc71d Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 27 Mar 2017 12:27:21 -0700 Subject: [PATCH 310/620] Changes as requested per Commit 9c90b21 In dnsapi/dns_dynu.sh line 115: export _H1="Authorization: Basic $(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" ^-- SC2155: Declare and assign separately to avoid masking return values. --- dnsapi/dns_dynu.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index b12b0bbb..c50c7a18 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -112,7 +112,9 @@ _dynu_rest() { } _dynu_authentication() { - export _H1="Authorization: Basic $(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" + realm = "$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" + + export _H1="Authorization: Basic $realm" export _H2="Content-Type: application/json" response="$(_get "$Dynu_EndPoint/oauth2/token")" From cd8fcbf9c63a9a60726fb2bc3a889df55fdf87dd Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 27 Mar 2017 12:38:12 -0700 Subject: [PATCH 311/620] Spaces in assignment removed. --- dnsapi/dns_dynu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index c50c7a18..19a24471 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -112,7 +112,7 @@ _dynu_rest() { } _dynu_authentication() { - realm = "$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" + realm="$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" export _H1="Authorization: Basic $realm" export _H2="Content-Type: application/json" From b7b934913ef0375700e3808801db5565b36ed193 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 27 Mar 2017 13:39:31 -0700 Subject: [PATCH 312/620] Removed unnecessary spaces --- dnsapi/dns_dynu.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 19a24471..b81840d0 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -42,7 +42,7 @@ dns_dynu_add() { if ! _get_root "$fulldomain"; then _err "Invalid domain" return 1 - fi + fi _debug _node "$_node" _debug _domain_name "$_domain_name" @@ -83,7 +83,7 @@ _get_root() { _domain_name=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 1 | cut -d : -f 2 | cut -d '"' -f 2) _node=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 3 | cut -d : -f 2 | cut -d '"' -f 2) - return 0 + return 0 } _dynu_rest() { @@ -113,7 +113,7 @@ _dynu_rest() { _dynu_authentication() { realm="$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" - + export _H1="Authorization: Basic $realm" export _H2="Content-Type: application/json" @@ -128,7 +128,7 @@ _dynu_authentication() { if _contains "$Dynu_Token" "null"; then Dynu_Token="" fi - + _debug2 response "$response" return 0 } From e137792efdb0986192b0b96cf728e670c4719c1b Mon Sep 17 00:00:00 2001 From: shar0119 Date: Tue, 28 Mar 2017 08:11:04 -0700 Subject: [PATCH 313/620] Commented out Dynu_ClientId and Dynu_Secret --- dnsapi/dns_dynu.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index b81840d0..03a45c1a 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -1,10 +1,10 @@ #!/usr/bin/env sh #Client ID -Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d" +#Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d" # #Secret -Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9" +#Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9" # #Token Dynu_Token="" From 58d4c74b0bc09e4f6480ad2845a81df8b882da61 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 29 Mar 2017 09:10:42 +0800 Subject: [PATCH 314/620] export Le_Domain for reloadcmd fix https://github.com/Neilpang/acme.sh/issues/558#issuecomment-289926193 --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index ce5b1dbd..28344c6d 100755 --- a/acme.sh +++ b/acme.sh @@ -4134,6 +4134,7 @@ _installcert() { export CERT_KEY_PATH export CA_CERT_PATH export CERT_FULLCHAIN_PATH + export Le_Domain cd "$DOMAIN_PATH" && eval "$_reload_cmd" ); then _info "$(__green "Reload success")" From 6cf7be4b7e8899e4ca1658027af535b40485afd3 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 29 Mar 2017 09:16:22 +0800 Subject: [PATCH 315/620] fix https://github.com/Neilpang/acme.sh/issues/751 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 28344c6d..7cb36afb 100755 --- a/acme.sh +++ b/acme.sh @@ -340,7 +340,7 @@ _hasfield() { _sep="," fi - for f in $(echo "$_str" | tr ',' ' '); do + for f in $(echo "$_str" | tr "$_sep" ' '); do if [ "$f" = "$_field" ]; then _debug2 "'$_str' contains '$_field'" return 0 #contains ok From d8ba26e664242338b4e10ae5c50320ef0122922d Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 30 Mar 2017 21:16:25 +0800 Subject: [PATCH 316/620] add retry for issuer cert --- acme.sh | 99 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 39 deletions(-) diff --git a/acme.sh b/acme.sh index 7cb36afb..3bd9b024 100755 --- a/acme.sh +++ b/acme.sh @@ -138,8 +138,8 @@ _printargs() { _dlg_versions() { echo "Diagnosis versions: " echo "openssl:$ACME_OPENSSL_BIN" - if _exists "$ACME_OPENSSL_BIN"; then - $ACME_OPENSSL_BIN version 2>&1 + if _exists "${ACME_OPENSSL_BIN:-openssl}"; then + ${ACME_OPENSSL_BIN:-openssl} version 2>&1 else echo "$ACME_OPENSSL_BIN doesn't exists." fi @@ -790,19 +790,19 @@ _base64() { [ "" ] #urgly if [ "$1" ]; then _debug3 "base64 multiline:'$1'" - $ACME_OPENSSL_BIN base64 -e + ${ACME_OPENSSL_BIN:-openssl} base64 -e else _debug3 "base64 single line." - $ACME_OPENSSL_BIN base64 -e | tr -d '\r\n' + ${ACME_OPENSSL_BIN:-openssl} base64 -e | tr -d '\r\n' fi } #Usage: multiline _dbase64() { if [ "$1" ]; then - $ACME_OPENSSL_BIN base64 -d -A + ${ACME_OPENSSL_BIN:-openssl} base64 -d -A else - $ACME_OPENSSL_BIN base64 -d + ${ACME_OPENSSL_BIN:-openssl} base64 -d fi } @@ -819,9 +819,9 @@ _digest() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then if [ "$outputhex" ]; then - $ACME_OPENSSL_BIN dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' + ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' else - $ACME_OPENSSL_BIN dgst -"$alg" -binary | _base64 + ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -binary | _base64 fi else _err "$alg is not supported yet" @@ -844,9 +844,9 @@ _hmac() { if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then if [ "$outputhex" ]; then - ($ACME_OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || $ACME_OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' ' + (${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' ' else - $ACME_OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || $ACME_OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary + ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary fi else _err "$alg is not supported yet" @@ -865,7 +865,7 @@ _sign() { return 1 fi - _sign_openssl="$ACME_OPENSSL_BIN dgst -sign $keyfile " + _sign_openssl="${ACME_OPENSSL_BIN:-openssl} dgst -sign $keyfile " if [ "$alg" = "sha256" ]; then _sign_openssl="$_sign_openssl -$alg" else @@ -876,7 +876,7 @@ _sign() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then $_sign_openssl | _base64 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then - if ! _signedECText="$($_sign_openssl | $ACME_OPENSSL_BIN asn1parse -inform DER)"; then + if ! _signedECText="$($_sign_openssl | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then _err "Sign failed: $_sign_openssl" _err "Key file: $keyfile" _err "Key content:$(wc -l <"$keyfile") lines" @@ -948,10 +948,10 @@ _createkey() { if _isEccKey "$length"; then _debug "Using ec name: $eccname" - $ACME_OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f" + ${ACME_OPENSSL_BIN:-openssl} ecparam -name "$eccname" -genkey 2>/dev/null >"$f" else _debug "Using RSA: $length" - $ACME_OPENSSL_BIN genrsa "$length" 2>/dev/null >"$f" + ${ACME_OPENSSL_BIN:-openssl} genrsa "$length" 2>/dev/null >"$f" fi if [ "$?" != "0" ]; then @@ -1038,9 +1038,9 @@ _createcsr() { _csr_cn="$(_idn "$domain")" _debug2 _csr_cn "$_csr_cn" if _contains "$(uname -a)" "MINGW"; then - $ACME_OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" + ${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" else - $ACME_OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" + ${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" fi } @@ -1052,7 +1052,7 @@ _signcsr() { cert="$4" _debug "_signcsr" - _msg="$($ACME_OPENSSL_BIN x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" + _msg="$(${ACME_OPENSSL_BIN:-openssl} x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" _ret="$?" _debug "$_msg" return $_ret @@ -1065,7 +1065,7 @@ _readSubjectFromCSR() { _usage "_readSubjectFromCSR mycsr.csr" return 1 fi - $ACME_OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' + ${ACME_OPENSSL_BIN:-openssl} req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' } #_csrfile @@ -1080,7 +1080,7 @@ _readSubjectAltNamesFromCSR() { _csrsubj="$(_readSubjectFromCSR "$_csrfile")" _debug _csrsubj "$_csrsubj" - _dnsAltnames="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" + _dnsAltnames="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" _debug _dnsAltnames "$_dnsAltnames" if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then @@ -1101,7 +1101,7 @@ _readKeyLengthFromCSR() { return 1 fi - _outcsr="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile")" + _outcsr="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile")" if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then _debug "ECC CSR" echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' @@ -1159,9 +1159,9 @@ toPkcs() { _initpath "$domain" "$_isEcc" if [ "$pfxPassword" ]; then - $ACME_OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" else - $ACME_OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" fi if [ "$?" = "0" ]; then @@ -1183,7 +1183,7 @@ toPkcs8() { _initpath "$domain" "$_isEcc" - $ACME_OPENSSL_BIN pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in "$CERT_KEY_PATH" -out "$CERT_PKCS8_PATH" + ${ACME_OPENSSL_BIN:-openssl} pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in "$CERT_KEY_PATH" -out "$CERT_PKCS8_PATH" if [ "$?" = "0" ]; then _info "Success, $CERT_PKCS8_PATH" @@ -1344,7 +1344,7 @@ _calcjwk() { if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "RSA key" - pub_exp=$($ACME_OPENSSL_BIN rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) + pub_exp=$(${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) if [ "${#pub_exp}" = "5" ]; then pub_exp=0$pub_exp fi @@ -1353,7 +1353,7 @@ _calcjwk() { e=$(echo "$pub_exp" | _h2b | _base64) _debug3 e "$e" - modulus=$($ACME_OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) + modulus=$(${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) _debug3 modulus "$modulus" n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)" _debug3 n "$n" @@ -1366,12 +1366,12 @@ _calcjwk() { JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then _debug "EC key" - crv="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" + crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv "$crv" if [ -z "$crv" ]; then _debug "Let's try ASN1 OID" - crv_oid="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" + crv_oid="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv_oid "$crv_oid" case "${crv_oid}" in "prime256v1") @@ -1391,15 +1391,15 @@ _calcjwk() { _debug3 crv "$crv" fi - pubi="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" + pubi="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" pubi=$(_math "$pubi" + 1) _debug3 pubi "$pubi" - pubj="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" + pubj="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" pubj=$(_math "$pubj" - 1) _debug3 pubj "$pubj" - pubtext="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" + pubtext="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" _debug3 pubtext "$pubtext" xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" @@ -2017,7 +2017,7 @@ _starttlsserver() { return 1 fi - __S_OPENSSL="$ACME_OPENSSL_BIN s_server -cert $TLS_CERT -key $TLS_KEY " + __S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -cert $TLS_CERT -key $TLS_KEY " if [ "$opaddr" ]; then __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" else @@ -3635,6 +3635,7 @@ issue() { _rcert="$response" Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" + _debug "Le_LinkCert" "$Le_LinkCert" _savedomainconf "Le_LinkCert" "$Le_LinkCert" if [ "$Le_LinkCert" ]; then @@ -3681,16 +3682,34 @@ issue() { if ! _contains "$Le_LinkIssuer" ":"; then Le_LinkIssuer="$API$Le_LinkIssuer" fi - + _debug Le_LinkIssuer "$Le_LinkIssuer" _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" if [ "$Le_LinkIssuer" ]; then - echo "$BEGIN_CERT" >"$CA_CERT_PATH" - _get "$Le_LinkIssuer" | _base64 "multiline" >>"$CA_CERT_PATH" - echo "$END_CERT" >>"$CA_CERT_PATH" - _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")" - cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH" - _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")" + _link_issuer_retry=0; + _MAX_ISSUER_RETRY=5; + while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do + _debug _link_issuer_retry "$_link_issuer_retry" + if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then + echo "$BEGIN_CERT" >"$CA_CERT_PATH" + _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" + echo "$END_CERT" >>"$CA_CERT_PATH" + + _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")" + cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH" + _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")" + + rm -f "$CA_CERT_PATH.der" + break + fi + _link_issuer_retry=$(_math $_link_issuer_retry + 1) + _sleep "$_link_issuer_retry" + done + if [ "$_link_issuer_retry" = "$_MAX_ISSUER_RETRY" ]; then + _err "Max retry for issuer ca cert is reached." + fi + else + _debug "No Le_LinkIssuer header found." fi Le_CertCreateTime=$(_time) @@ -4463,7 +4482,7 @@ _precheck() { fi fi - if ! _exists "$ACME_OPENSSL_BIN"; then + if ! _exists "${ACME_OPENSSL_BIN:-openssl}"; then _err "Please install openssl first. ACME_OPENSSL_BIN=$ACME_OPENSSL_BIN" _err "We need openssl to generate keys." return 1 @@ -4705,6 +4724,7 @@ _uninstallalias() { cron() { IN_CRON=1 _initpath + _info "$(__green "===Starting cron===")" if [ "$AUTO_UPGRADE" = "1" ]; then export LE_WORKING_DIR ( @@ -4724,6 +4744,7 @@ cron() { renewAll _ret="$?" IN_CRON="" + _info "$(__green "===End cron===")" exit $_ret } From 232c7361a94cd0959abe175ccb7d5fdab43aefce Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 30 Mar 2017 21:34:15 +0800 Subject: [PATCH 317/620] fix format --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 3bd9b024..99525459 100755 --- a/acme.sh +++ b/acme.sh @@ -3686,8 +3686,8 @@ issue() { _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" if [ "$Le_LinkIssuer" ]; then - _link_issuer_retry=0; - _MAX_ISSUER_RETRY=5; + _link_issuer_retry=0 + _MAX_ISSUER_RETRY=5 while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do _debug _link_issuer_retry "$_link_issuer_retry" if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then From f3b434397b9928e36c7303ffaa9bbb8cf711bfc2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 3 Apr 2017 12:08:38 +0800 Subject: [PATCH 318/620] v2.6.8 support Docker --- Dockerfile | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 ++ acme.sh | 2 +- 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..8d0f6185 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,52 @@ +FROM alpine + +RUN apk update -f \ + && apk --no-cache add -f \ + openssl \ + curl \ + netcat-openbsd + +ENV LE_CONFIG_HOME /acme.sh + +ENV AUTO_UPGRADE 1 + +#Install +RUN mkdir -p /install_acme.sh/ +ADD ./ /install_acme.sh/ +RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) +RUN rm -rf /install_acme.sh/ + +RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh + +RUN for verb in help \ + version \ + install \ + uninstall \ + upgrade \ + issue \ + signcsr \ + deploy \ + install-cert \ + renew \ + renew-all \ + revoke \ + remove \ + list \ + showcsr \ + install-cronjob \ + uninstall-cronjob \ + cron \ + toPkcs \ + toPkcs8 \ + update-account \ + register-account \ + create-account-key \ + create-domain-key \ + createCSR \ + deactivate \ + ; 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 + +ENTRYPOINT ["/root/.acme.sh/acme.sh", "--config-home", "/acme.sh"] +CMD ["--help"] diff --git a/README.md b/README.md index 7a79bed4..e0c1e7d6 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,13 @@ - Purely written in Shell with no dependencies on python or the official Let's Encrypt client. - Just one script to issue, renew and install your certificates automatically. - DOES NOT require `root/sudoer` access. +- Docker friendly It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. Wiki: https://github.com/Neilpang/acme.sh/wiki +For Docker Fans: [acme.sh :two_hearts: Docker ](https://github.com/Neilpang/acme.sh/wiki/Run-acme.sh-in-docker) Twitter: [@neilpangxa](https://twitter.com/neilpangxa) diff --git a/acme.sh b/acme.sh index 99525459..e2bc928f 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.7 +VER=2.6.8 PROJECT_NAME="acme.sh" From 1f4e64f81d7650e7811153cf73e527b94fc252c1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 00:21:39 +0800 Subject: [PATCH 319/620] Truncated request for more than 100 domains. --- dnsapi/dns_aws.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index d5d52de0..6fffd093 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -88,6 +88,19 @@ _get_root() { while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then + if _contains "$response" "true" && _contains "$response" ""; then + _debug "IsTruncated" + _nextMarker="$(echo "$response" | _egrep_o ".*" | cut -d '>' -f 2 | cut -d '<' -f 1)" + _debug "NextMarker" "$_nextMarker" + if aws_rest GET "2013-04-01/hostedzone?marker=$_nextMarker"; then + _debug "Truncated request OK" + i=2 + p=1 + continue + else + _err "Truncated request error." + fi + fi #not valid return 1 fi From 66e38ae69e4487155cbc555f1230ac641e2b5f5a Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 3 Apr 2017 13:46:39 -0700 Subject: [PATCH 320/620] Updated Readme.md file (1 of 2) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e0c1e7d6..567ec5ba 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,7 @@ You don't have to do anything manually! 1. DigitalOcean API (native) 1. ClouDNS.net API 1. Infoblox NIOS API (https://www.infoblox.com/) +1. Dynu API (https://www.dynu.com) **More APIs coming soon...** From afb67d375facf5065326362f2046452ee039bc94 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 3 Apr 2017 14:01:40 -0700 Subject: [PATCH 321/620] Updated README.md (2 of 2) --- dnsapi/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index 9eb77915..e8c263b0 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -438,6 +438,22 @@ 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 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. + # Use custom API If your API is not supported yet, you can write your own DNS API. From fc9649dbc48bc89626d0f80fd7db20442cb17f0e Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 10:02:45 +0800 Subject: [PATCH 322/620] fix aws --- dnsapi/dns_aws.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 6fffd093..137af895 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -92,7 +92,7 @@ _get_root() { _debug "IsTruncated" _nextMarker="$(echo "$response" | _egrep_o ".*" | cut -d '>' -f 2 | cut -d '<' -f 1)" _debug "NextMarker" "$_nextMarker" - if aws_rest GET "2013-04-01/hostedzone?marker=$_nextMarker"; then + if aws_rest GET "2013-04-01/hostedzone" "marker=$_nextMarker"; then _debug "Truncated request OK" i=2 p=1 @@ -220,7 +220,7 @@ aws_rest() { _H2="Authorization: $Authorization" _debug _H2 "$_H2" - url="$AWS_URL/$ep" + url="$AWS_URL/$ep?$qsr" if [ "$mtd" = "GET" ]; then response="$(_get "$url")" From 695482ded7248b25ecaa23e00571dd32d04f4ad4 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 3 Apr 2017 21:21:50 -0700 Subject: [PATCH 323/620] Added author name and link to report bugs --- dnsapi/dns_dynu.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 03a45c1a..9bf2c064 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -11,7 +11,10 @@ Dynu_Token="" # #Endpoint Dynu_EndPoint="https://api.dynu.com/v1" - +# +#Author: David Kerr +#Report Bugs here: https://github.com/dkerr64/acme.sh +# ######## Public functions ##################### #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" From 6d7f6750e94bc969fed6469bff6402be538987a8 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Mon, 3 Apr 2017 21:22:58 -0700 Subject: [PATCH 324/620] Updated author name and link to report bugs --- dnsapi/dns_dynu.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 9bf2c064..63992ed4 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -12,8 +12,8 @@ Dynu_Token="" #Endpoint Dynu_EndPoint="https://api.dynu.com/v1" # -#Author: David Kerr -#Report Bugs here: https://github.com/dkerr64/acme.sh +#Author: Dynu Systems, Inc. +#Report Bugs here: https://github.com/shar0119/acme.sh # ######## Public functions ##################### From fd77e463a150e2253aa7ca6658c17bddb62fef79 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 14:34:23 +0800 Subject: [PATCH 325/620] fix aws --- dnsapi/dns_aws.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 137af895..6a723537 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -220,7 +220,10 @@ aws_rest() { _H2="Authorization: $Authorization" _debug _H2 "$_H2" - url="$AWS_URL/$ep?$qsr" + url="$AWS_URL/$ep" + if [ "$qsr" ]; then + url="$AWS_URL/$ep?$qsr" + fi if [ "$mtd" = "GET" ]; then response="$(_get "$url")" From f7217c5f2629d541a4584039a7d9c9313afdda7f Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 15:54:45 +0800 Subject: [PATCH 326/620] fix format --- 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 6a723537..21e86686 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -88,7 +88,7 @@ _get_root() { while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then - if _contains "$response" "true" && _contains "$response" ""; then + if _contains "$response" "true" && _contains "$response" ""; then _debug "IsTruncated" _nextMarker="$(echo "$response" | _egrep_o ".*" | cut -d '>' -f 2 | cut -d '<' -f 1)" _debug "NextMarker" "$_nextMarker" From 7df062b7d7d9ff95f6a3b58f005431ccd3cd4ec8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Apr 2017 22:33:26 +0800 Subject: [PATCH 327/620] add more debug info --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index e2bc928f..8f47f8cc 100755 --- a/acme.sh +++ b/acme.sh @@ -1102,6 +1102,7 @@ _readKeyLengthFromCSR() { fi _outcsr="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile")" + _debug2 _outcsr "$_outcsr" if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then _debug "ECC CSR" echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' From 49d75a0cd4ba5112ca947a2b54ba72719ac4f73b Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 5 Apr 2017 20:46:17 +0800 Subject: [PATCH 328/620] minor, add more error message --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index 8f47f8cc..850ac4b1 100755 --- a/acme.sh +++ b/acme.sh @@ -3121,6 +3121,10 @@ issue() { _usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ " return 1 fi + if [ -z "$1" ]; then + _usage "Please specify at least one validation method: '--webroot', '--standalone', '--apache', '--nginx' or '--dns' etc." + return 1 + fi _web_roots="$1" _main_domain="$2" _alt_domains="$3" From 3576754c217c643d9b66cba0e91d858ada5781bf Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 5 Apr 2017 20:54:53 +0800 Subject: [PATCH 329/620] fix https://github.com/Neilpang/acme.sh/issues/549 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 850ac4b1..b6b0c842 100755 --- a/acme.sh +++ b/acme.sh @@ -107,7 +107,7 @@ __green() { if [ "$__INTERACTIVE" ]; then printf '\033[1;31;32m' fi - printf -- "$1" + printf -- "%b" "$1" if [ "$__INTERACTIVE" ]; then printf '\033[0m' fi @@ -117,7 +117,7 @@ __red() { if [ "$__INTERACTIVE" ]; then printf '\033[1;31;40m' fi - printf -- "$1" + printf -- "%b" "$1" if [ "$__INTERACTIVE" ]; then printf '\033[0m' fi From 482cb737025d691c730594abf8084c0bd1936bc6 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 6 Apr 2017 19:29:09 +0800 Subject: [PATCH 330/620] fix https://github.com/Neilpang/acme.sh/issues/758 --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index b6b0c842..11a30fa9 100755 --- a/acme.sh +++ b/acme.sh @@ -1105,10 +1105,10 @@ _readKeyLengthFromCSR() { _debug2 _outcsr "$_outcsr" if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then _debug "ECC CSR" - echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' + echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' else _debug "RSA CSR" - echo "$_outcsr" | _egrep_o "(^ *|^RSA )Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 + echo "$_outcsr" | tr "\t" " " | _egrep_o "(^ *|RSA )Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 fi } @@ -3865,7 +3865,7 @@ renewAll() { return "$rc" else _ret="$rc" - _err "Error renew $d, Go ahead to next one." + _err "Error renew $d." fi fi done From 7f618e7ecc698f171135558b34b6980219b902d7 Mon Sep 17 00:00:00 2001 From: Kok Suan Lim Date: Sat, 8 Apr 2017 14:50:39 +0800 Subject: [PATCH 331/620] fix missing space bug on if statement --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 11a30fa9..f434f685 100755 --- a/acme.sh +++ b/acme.sh @@ -2565,7 +2565,7 @@ _checkConf() { if [ ! -f "$2" ] && ! echo "$2" | grep '*$' >/dev/null && echo "$2" | grep '*' >/dev/null; then _debug "wildcard" for _w_f in $2; do - if [ -f "$_w_f"] && _checkConf "$1" "$_w_f"; then + if [ -f "$_w_f" ] && _checkConf "$1" "$_w_f"; then return 0 fi done From fcdf41ba293658060e82c45b3c3ec368db270385 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 11 Apr 2017 21:37:56 +0800 Subject: [PATCH 332/620] support change account conf from env --- acme.sh | 20 +++++++++++++++++++- dnsapi/dns_cf.sh | 6 ++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index f434f685..3498fe75 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.8 +VER=2.6.9 PROJECT_NAME="acme.sh" @@ -1847,6 +1847,24 @@ _saveaccountconf() { _save_conf "$ACCOUNT_CONF_PATH" "$1" "$2" } +#key value +_saveaccountconf_mutable() { + _save_conf "$ACCOUNT_CONF_PATH" "SAVED_$1" "$2" + #remove later + _clearaccountconf "$1" +} + +#key +_readaccountconf() { + _read_conf "$ACCOUNT_CONF_PATH" "$1" +} + +#key +_readaccountconf_mutable() { + _rac_key="$1" + _readaccountconf "SAVED_$_rac_key" +} + #_clearaccountconf key _clearaccountconf() { _clear_conf "$ACCOUNT_CONF_PATH" "$1" diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 3718f9db..0442fbe0 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -14,6 +14,8 @@ 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="" @@ -29,8 +31,8 @@ dns_cf_add() { fi #save the api key and email to the account conf file. - _saveaccountconf CF_Key "$CF_Key" - _saveaccountconf CF_Email "$CF_Email" + _saveaccountconf_mutable CF_Key "$CF_Key" + _saveaccountconf_mutable CF_Email "$CF_Email" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then From eb0fc67461c07ed5eeae8605d616e88ec9b985dc Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 11 Apr 2017 22:29:49 +0800 Subject: [PATCH 333/620] fix format --- 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 0442fbe0..228caa82 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -14,8 +14,8 @@ dns_cf_add() { fulldomain=$1 txtvalue=$2 - CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key )}" - CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email )}" + 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="" From 9a61d6293d14a401f57fed793b9b829788c5b134 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Thu, 13 Apr 2017 20:48:39 -0700 Subject: [PATCH 334/620] Implemented dns_dynu_rm() Implemented dns_dynu_rm() method. --- dnsapi/dns_dynu.sh | 93 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 63992ed4..a3a604ba 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -35,7 +35,7 @@ dns_dynu_add() { _saveaccountconf Dynu_Secret "$Dynu_Secret" if [ -z "$Dynu_Token" ]; then - _info "Getting Dynu token" + _info "Getting Dynu token." if ! _dynu_authentication; then _err "Can not get token." fi @@ -43,29 +43,76 @@ dns_dynu_add() { _debug "Detect root zone" if ! _get_root "$fulldomain"; then - _err "Invalid domain" + _err "Invalid domain." return 1 fi _debug _node "$_node" _debug _domain_name "$_domain_name" - _info "Creating TXT record" + _info "Creating TXT record." if ! _dynu_rest POST "dns/record/add" "{\"domain_name\":\"$_domain_name\",\"node_name\":\"$_node\",\"record_type\":\"TXT\",\"text_data\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then return 1 fi if ! _contains "$response" "text_data"; then - _err "Could not add TXT record" + _err "Could not add TXT record." return 1 fi return 0 } -#fulldomain +#Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_dynu_rm() { fulldomain=$1 + txtvalue=$2 + + if [ -z "$Dynu_ClientId" ] || [ -z "$Dynu_Secret" ]; then + Dynu_ClientId="" + Dynu_Secret="" + _err "Dynu client id and secret is not specified." + _err "Please create you API client id and secret and try again." + return 1 + fi + + #save the client id and secret to the account conf file. + _saveaccountconf Dynu_ClientId "$Dynu_ClientId" + _saveaccountconf Dynu_Secret "$Dynu_Secret" + + if [ -z "$Dynu_Token" ]; then + _info "Getting Dynu token." + if ! _dynu_authentication; then + _err "Can not get token." + fi + fi + + _debug "Detect root zone." + if ! _get_root "$fulldomain"; then + _err "Invalid domain." + return 1 + fi + + _debug _node "$_node" + _debug _domain_name "$_domain_name" + + _info "Checking for TXT record." + if ! _get_recordid "$fulldomain" "$txtvalue"; then + _err "Could not get TXT record id." + return 1 + fi + + if [ "$_dns_record_id" = "" ]; then + _err "TXT record not found." + return 1 + fi + + _info "Removing TXT record." + if ! _delete_txt_record "$_dns_record_id"; then + _err "Could not remove TXT record $_dns_record_id." + fi + + return 0 } ######## Private functions below ################################## @@ -80,7 +127,7 @@ _get_root() { fi if ! _contains "$response" "domain_name"; then - _debug "Domain name not found" + _debug "Domain name not found." return 1 fi @@ -89,6 +136,38 @@ _get_root() { return 0 } +_get_recordid() { + fulldomain=$1 + txtvalue=$2 + + if ! _dynu_rest GET "dns/record/get?hostname=$fulldomain&rrtype=TXT"; then + return 1 + fi + + if ! _contains "$response" "$txtvalue"; then + _dns_record_id=0 + return 0 + fi + + _dns_record_id=$(printf "%s" "$response" grep -o -e "{[^}]*}" | grep '"text_data":"This is another TXT record."' | grep -o -e ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2) + + return 0 +} + +_delete_txt_record() { + _dns_record_id=$1 + + if ! _dynu_rest GET "dns/record/delete/$_dns_record_id"; then + return 1 + fi + + if ! _contains "$response" "true"; then + return 1 + fi + + return 0 +} + _dynu_rest() { m=$1 ep="$2" @@ -102,7 +181,7 @@ _dynu_rest() { _debug data "$data" response="$(_post "$data" "$Dynu_EndPoint/$ep" "" "$m")" else - echo "Getting $Dynu_EndPoint/$ep" + _info "Getting $Dynu_EndPoint/$ep" response="$(_get "$Dynu_EndPoint/$ep")" fi From 394b1002b344db16ef8568f2933b162d9e87c9c5 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Thu, 13 Apr 2017 20:54:57 -0700 Subject: [PATCH 335/620] Corrected formatting error. Part of dns_dynu_rm() impementation. --- dnsapi/dns_dynu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index a3a604ba..e784c3b8 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -112,7 +112,7 @@ dns_dynu_rm() { _err "Could not remove TXT record $_dns_record_id." fi - return 0 + return 0 } ######## Private functions below ################################## From 8470c60e067b522e3322f90bca980313ac110729 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Fri, 14 Apr 2017 12:46:00 -0700 Subject: [PATCH 336/620] Using _egrep_o() instead of grep -o -e Modified code to use egrep instead of grep -o -e. --- dnsapi/dns_dynu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index e784c3b8..19e7fc7b 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -149,7 +149,7 @@ _get_recordid() { return 0 fi - _dns_record_id=$(printf "%s" "$response" grep -o -e "{[^}]*}" | grep '"text_data":"This is another TXT record."' | grep -o -e ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2) + _dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | grep -Po '"id":\K[0-9]+') return 0 } From cd98951001ca5f9bbd79a6e35bca3653b1b1e0d8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 16 Apr 2017 09:36:59 +0800 Subject: [PATCH 337/620] fix https://github.com/Neilpang/acme.sh/issues/794#issuecomment-294314606 --- dnsapi/dns_cf.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dnsapi/dns_cf.sh b/dnsapi/dns_cf.sh index 228caa82..57a2e884 100755 --- a/dnsapi/dns_cf.sh +++ b/dnsapi/dns_cf.sh @@ -85,6 +85,17 @@ dns_cf_add() { 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 don't specify cloudflare api key and email yet." + _err "Please create you key and try again." + return 1 + fi + _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" From 7883cc58912418d96cf4f2eff5dac8e15015aa4d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 16 Apr 2017 11:16:48 +0800 Subject: [PATCH 338/620] fix docker cronjob --- Dockerfile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 8d0f6185..feb89b0d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -48,5 +48,12 @@ RUN for verb in help \ 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 -ENTRYPOINT ["/root/.acme.sh/acme.sh", "--config-home", "/acme.sh"] +RUN printf "%b" '#!'"/usr/bin/env sh\n \ +if [ \"\$1\" = \"daemon\" ]; then \n \ + crond; tail -f /dev/null;\n \ +else \n \ + /root/.acme.sh/acme.sh --config-home /acme.sh \"\$@\"\n \ +fi" >/entry.sh && chmod +x /entry.sh + +ENTRYPOINT ["/entry.sh"] CMD ["--help"] From 3c07f57aade6d3995f16faa5f3ed3fac8d962d01 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 17 Apr 2017 19:08:34 +0800 Subject: [PATCH 339/620] minor remove spaces --- acme.sh | 26 +++++++++++++------------- dnsapi/dns_freedns.sh | 6 +++--- dnsapi/dns_ovh.sh | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/acme.sh b/acme.sh index 3498fe75..27bc4fb3 100755 --- a/acme.sh +++ b/acme.sh @@ -347,7 +347,7 @@ _hasfield() { fi done _debug2 "'$_str' does not contain '$_field'" - return 1 #not contains + return 1 #not contains } _getfield() { @@ -722,7 +722,7 @@ _url_encode() { "7e") printf "%s" "~" ;; - #other hex + #other hex *) printf '%%%s' "$_hex_code" ;; @@ -1025,7 +1025,7 @@ _createcsr() { else alt="DNS:$domainlist" fi - #multi + #multi _info "Multi domain" "$alt" printf -- "\nsubjectAltName=$alt" >>"$csrconf" fi @@ -1093,7 +1093,7 @@ _readSubjectAltNamesFromCSR() { printf "%s" "$_dnsAltnames" | sed "s/DNS://g" } -#_csrfile +#_csrfile _readKeyLengthFromCSR() { _csrfile="$1" if [ -z "$_csrfile" ]; then @@ -1192,7 +1192,7 @@ toPkcs8() { } -#[2048] +#[2048] createAccountKey() { _info "Creating account key" if [ -z "$1" ]; then @@ -2546,7 +2546,7 @@ _setNginx() { location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { default_type text/plain; return 200 \"\$1.$_thumbpt\"; -} +} #NGINX_START " >>"$FOUND_REAL_NGINX_CONF" @@ -3133,7 +3133,7 @@ __trigger_validation() { _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" } -#webroot, domain domainlist keylength +#webroot, domain domainlist keylength issue() { if [ -z "$2" ]; then _usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ " @@ -3666,7 +3666,7 @@ issue() { #if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then # _debug "Get cert failed. Let's try last response." - # printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH" + # printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH" #fi if ! printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >>"$CERT_PATH"; then @@ -4807,7 +4807,7 @@ Commands: --create-domain-key Create an domain private key, professional use. --createCSR, -ccsr Create CSR , professional use. --deactivate Deactivate the domain authz, professional use. - + Parameters: --domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc. --force, -f Used to force to install or force to renew a cert immediately. @@ -4821,20 +4821,20 @@ Parameters: --apache Use apache mode. --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api. --dnssleep [$DEFAULT_DNS_SLEEP] The time in seconds to wait for all the txt records to take effect in dns api mode. Default $DEFAULT_DNS_SLEEP seconds. - + --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384. --accountkeylength, -ak [2048] Specifies the account key length. --log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here. --log-level 1|2 Specifies the log level, default is 1. --syslog [0|3|6|7] Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug. - + These parameters are to install the cert to nginx/apache or anyother 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. --ca-file After issue/renew, the intermediate cert will be copied to this path. --fullchain-file After issue/renew, the fullchain cert will be copied to this path. - + --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. --accountconf Specifies a customized account config file. diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 272a1243..53da4118 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -53,7 +53,7 @@ dns_freedns_add() { i="$(_math "$i" - 1)" sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" - # Sometimes FreeDNS does not return the subdomain page but rather + # 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 @@ -72,7 +72,7 @@ dns_freedns_add() { fi # Now convert the tables in the HTML to CSV. This litte gem from - # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv + # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv subdomain_csv="$(echo "$htmlpage" \ | grep -i -e ' Date: Wed, 19 Apr 2017 23:12:37 +0800 Subject: [PATCH 340/620] update doc --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e0c1e7d6..cf825625 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ - DOES NOT require `root/sudoer` access. - Docker friendly -It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. +It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. Wiki: https://github.com/Neilpang/acme.sh/wiki @@ -31,6 +31,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) - [Centminmod](http://centminmod.com/letsencrypt-acmetool-https.html) - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) - [archlinux](https://aur.archlinux.org/packages/acme.sh-git/) +- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient) - [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) # Tested OS From 27a05ff27112a29e98aa51661040ef3176c07531 Mon Sep 17 00:00:00 2001 From: LAV45 Date: Sat, 15 Apr 2017 14:34:37 +0300 Subject: [PATCH 341/620] Add dns_vscale.sh --- README.md | 1 + dnsapi/README.md | 15 +++++ dnsapi/dns_vscale.sh | 149 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100755 dnsapi/dns_vscale.sh diff --git a/README.md b/README.md index e0c1e7d6..47ea0126 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,7 @@ You don't have to do anything manually! 1. DigitalOcean API (native) 1. ClouDNS.net API 1. Infoblox NIOS API (https://www.infoblox.com/) +1. VSCALE (https://vscale.io/) **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 9eb77915..896dfcb7 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -438,6 +438,21 @@ 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. + +## 22. Use VSCALE API + +First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). + +``` +VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns vscale -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_vscale.sh b/dnsapi/dns_vscale.sh new file mode 100755 index 00000000..e50b7d8b --- /dev/null +++ b/dnsapi/dns_vscale.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env sh + +#This is the vscale.io api wrapper for acme.sh +# +#Author: Alex Loban +#Report Bugs here: https://github.com/LAV45/acme.sh + +#VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" +VSCALE_API_URL="https://api.vscale.io/v1" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_vscale_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$VSCALE_API_KEY" ]; then + VSCALE_API_KEY="" + _err "You didn't specify the VSCALE api key yet." + _err "Please create you key and try again." + return 1 + fi + + _saveaccountconf VSCALE_API_KEY "$VSCALE_API_KEY" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _vscale_tmpl_json="{\"type\":\"TXT\",\"name\":\"$_sub_domain.$_domain\",\"content\":\"$txtvalue\"}" + + if _vscale_rest POST "domains/$_domain_id/records/" "$_vscale_tmpl_json"; then + response=$(printf "%s\n" "$response" | _egrep_o "{\"error\": \".+\"" | cut -d : -f 2) + if [ -z "$response" ]; then + _info "txt record updated success." + return 0 + fi + fi + + return 1 +} + +#fulldomain txtvalue +dns_vscale_rm() { + fulldomain=$1 + txtvalue=$2 + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _vscale_rest GET "domains/$_domain_id/records/" + + if [ -n "$response" ]; then + record_id=$(printf "%s\n" "$response" | _egrep_o "\"TXT\", \"id\": [0-9]+, \"name\": \"$_sub_domain.$_domain\"" | cut -d : -f 2 | tr -d ", \"name\"") + _debug record_id "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if _vscale_rest DELETE "domains/$_domain_id/records/$record_id" && [ -z "$response" ]; then + _info "txt record deleted success." + return 0 + fi + _debug response "$response" + return 1 + fi + + return 1 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=12345 +_get_root() { + domain=$1 + i=2 + p=1 + + if _vscale_rest GET "domains/"; then + response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + hostedzone="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$h\".*}")" + if [ "$hostedzone" ]; then + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + fi + return 1 +} + +#method uri qstr data +_vscale_rest() { + mtd="$1" + ep="$2" + data="$3" + + _debug mtd "$mtd" + _debug ep "$ep" + + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + export _H3="X-Token: ${VSCALE_API_KEY}" + + if [ "$mtd" != "GET" ]; then + # both POST and DELETE. + _debug data "$data" + response="$(_post "$data" "$VSCALE_API_URL/$ep" "" "$mtd")" + else + response="$(_get "$VSCALE_API_URL/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From dbe68684a054a11a6232803bafd0ba952380bc54 Mon Sep 17 00:00:00 2001 From: Aleksey Loban Date: Fri, 21 Apr 2017 12:30:01 +0300 Subject: [PATCH 342/620] Fix readme 'Use VSCALE API' [skip ci] --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 896dfcb7..82b47648 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -449,7 +449,7 @@ VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" Ok, let's issue a cert now: ``` -acme.sh --issue --dns vscale -d example.com -d www.example.com +acme.sh --issue --dns dns_vscale -d example.com -d www.example.com ``` From 020f9cd2a640a5347e46a650fdc4a3e059868ddc Mon Sep 17 00:00:00 2001 From: Aleksey Loban Date: Fri, 21 Apr 2017 13:15:39 +0300 Subject: [PATCH 343/620] small Fix readme [skip ci] --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 82b47648..d9f5c271 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -439,7 +439,7 @@ 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. -## 22. Use VSCALE API +## 23. Use VSCALE API First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). From a6e5876d964373c9fb68a16283f1097fb8b330c6 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Tue, 25 Apr 2017 19:33:54 -0700 Subject: [PATCH 344/620] Resolved conflict. Resolved conflict. --- dnsapi/README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index e8c263b0..41cc80a8 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -438,7 +438,21 @@ 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 Dynu API + +## 23. Use VSCALE API + +First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). + +``` +VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_vscale -d example.com -d www.example.com +``` + +## 24. Use Dynu API First you need to create/obtain API credentials from your Dynu account. See: https://www.dynu.com/resources/api/documentation From 9cf65e31cd599e567498d2d7972d858857d629b8 Mon Sep 17 00:00:00 2001 From: shar0119 Date: Tue, 25 Apr 2017 19:37:56 -0700 Subject: [PATCH 345/620] Resolved conflict. Resolved conflict. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 567ec5ba..cdcd40c3 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ - DOES NOT require `root/sudoer` access. - Docker friendly -It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. +It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. Wiki: https://github.com/Neilpang/acme.sh/wiki @@ -31,6 +31,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) - [Centminmod](http://centminmod.com/letsencrypt-acmetool-https.html) - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) - [archlinux](https://aur.archlinux.org/packages/acme.sh-git/) +- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient) - [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) # Tested OS @@ -313,6 +314,7 @@ You don't have to do anything manually! 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) **More APIs coming soon...** From 0138e167e91164bffc86eee29b4f140a1d03c93e Mon Sep 17 00:00:00 2001 From: thecantero Date: Thu, 27 Apr 2017 18:23:43 +0800 Subject: [PATCH 346/620] Update to support Kong-v0.10.x The previous one is for Kong-v0.9.x only. This change will allow it to work with v0.10.x. More info at: https://github.com/Mashape/kong/blob/4f960abe33fe3d45510944f062e571d63dc3a673/UPGRADE.md#upgrade-to-010x https://getkong.org/docs/0.10.x/admin-api/#add-certificate --- deploy/kong.sh | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index e1873f35..67eef693 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -31,14 +31,15 @@ kong_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - #Get uuid linked to the domain - uuid=$(_get "$KONG_URL/apis?request_host=$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') - if [ -z "$uuid" ]; then - _err "Unable to get Kong uuid for domain $_cdomain" - _err "Make sure that KONG_URL is correctly configured" - _err "Make sure that a Kong api request_host match the domain" - _err "Kong url: $KONG_URL" - return 1 + #Get ssl_uuid linked to the domain + ssl_uuid=$(_get "$KONG_URL/certificates/$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') + if [ -z "$ssl_uuid" ]; then + _debug "Unable to get Kong ssl_uuid for domain $_cdomain" + _debug "Make sure that KONG_URL is correctly configured" + _debug "Make sure that a Kong certificate match the sni" + _debug "Kong url: $KONG_URL" + _info "No existing certificate, creating..." + #return 1 fi #Save kong url if it's succesful (First run case) _saveaccountconf KONG_URL "$KONG_URL" @@ -48,12 +49,15 @@ kong_deploy() { #Set Header _H1="Content-Type: multipart/form-data; boundary=$delim" #Generate data for request (Multipart/form-data with mixed content) - #set name to ssl - content="--$delim${nl}Content-Disposition: form-data; name=\"name\"${nl}${nl}ssl" + content="--$delim${nl}" + if [ -z "$ssl_uuid" ]; then + #set sni to domain + content="$content{nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain" + fi #add key - content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"config.key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" #Add cert - content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"config.cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")" #Close multipart content="$content${nl}--$delim--${nl}" #Convert CRLF @@ -61,17 +65,16 @@ kong_deploy() { #DEBUG _debug header "$_H1" _debug content "$content" - #Check if ssl plugins is aready enabled (if not => POST else => PATCH) - ssl_uuid=$(_get "$KONG_URL/apis/$uuid/plugins" | _egrep_o '"id":"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"[a-zA-Z0-9\-\,\"_\:]*"name":"ssl"' | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') - _debug ssl_uuid "$ssl_uuid" + #Check if sslcreated (if not => POST else => PATCH) + if [ -z "$ssl_uuid" ]; then #Post certificate to Kong - response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins" "" "POST") + response=$(_post "$content" "$KONG_URL/certificates" "" "POST") else #patch - response=$(_post "$content" "$KONG_URL/apis/$uuid/plugins/$ssl_uuid" "" "PATCH") + response=$(_post "$content" "$KONG_URL/certificates/$ssl_uuid" "" "PATCH") fi - if ! [ "$(echo "$response" | _egrep_o "ssl")" = "ssl" ]; then + if ! [ "$(echo "$response" | _egrep_o "created_at")" = "created_at" ]; then _err "An error occurred with cert upload. Check response:" _err "$response" return 1 From 3f1a76d9e4e8cb1ab79816db81df73dd663cca1a Mon Sep 17 00:00:00 2001 From: neil Date: Thu, 27 Apr 2017 18:29:29 +0800 Subject: [PATCH 347/620] fix https://github.com/Neilpang/acme.sh/issues/808 --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 27bc4fb3..3506bdb9 100755 --- a/acme.sh +++ b/acme.sh @@ -2617,10 +2617,10 @@ _checkConf() { _isRealNginxConf() { _debug "_isRealNginxConf $1 $2" if [ -f "$2" ]; then - for _fln in $(grep -n "^ *server_name.* $1" "$2" | cut -d : -f 1); do + for _fln in $(tr "\t" ' ' <"$2" | grep -n "^ *server_name.* $1" | cut -d : -f 1); do _debug _fln "$_fln" if [ "$_fln" ]; then - _start=$(cat "$2" | _head_n "$_fln" | grep -n "^ *server *{" | _tail_n 1) + _start=$(tr "\t" ' ' <"$2" | _head_n "$_fln" | grep -n "^ *server *{" | _tail_n 1) _debug "_start" "$_start" _start_n=$(echo "$_start" | cut -d : -f 1) _start_nn=$(_math $_start_n + 1) @@ -2629,8 +2629,8 @@ _isRealNginxConf() { _left="$(sed -n "${_start_nn},99999p" "$2")" _debug2 _left "$_left" - if echo "$_left" | grep -n "^ *server *{" >/dev/null; then - _end=$(echo "$_left" | grep -n "^ *server *{" | _head_n 1) + if echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" >/dev/null; then + _end=$(echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" | _head_n 1) _debug "_end" "$_end" _end_n=$(echo "$_end" | cut -d : -f 1) _debug "_end_n" "$_end_n" From de3bac53bfb99e1b192bed48a1c5dcf694e2a606 Mon Sep 17 00:00:00 2001 From: thecantero Date: Thu, 27 Apr 2017 20:06:47 +0800 Subject: [PATCH 348/620] update README --- deploy/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index d8c2f57c..232fdb4a 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -21,8 +21,11 @@ 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. -(TODO) +```sh +acme.sh --deploy -d ftp.example.com --deploy-hook kong +``` ## 3. Deploy the cert to remote server through SSH access. From 4b02ee5b468814b2a19e9dd783b458264acbe776 Mon Sep 17 00:00:00 2001 From: thecantero Date: Thu, 27 Apr 2017 20:38:08 +0800 Subject: [PATCH 349/620] Typo fix --- deploy/kong.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 67eef693..79dc3916 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -67,7 +67,7 @@ kong_deploy() { _debug content "$content" #Check if sslcreated (if not => POST else => PATCH) - if [ -z "$ssl_uuid" ]; then + if [ ! -z "$ssl_uuid" ]; then #Post certificate to Kong response=$(_post "$content" "$KONG_URL/certificates" "" "POST") else From c140fe9bae8926e3724545330505edc3e1355833 Mon Sep 17 00:00:00 2001 From: thecantero Date: Thu, 27 Apr 2017 20:39:53 +0800 Subject: [PATCH 350/620] Typo Fix --- deploy/kong.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index 79dc3916..9d1f40a7 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -1,6 +1,3 @@ -#!/usr/bin/env sh - -# This deploy hook will deploy ssl cert on kong proxy engine based on api request_host parameter. # Note that ssl plugin should be available on Kong instance # The hook will match cdomain to request_host, in case of multiple domain it will always take the first # one (acme.sh behaviour). @@ -49,10 +46,9 @@ kong_deploy() { #Set Header _H1="Content-Type: multipart/form-data; boundary=$delim" #Generate data for request (Multipart/form-data with mixed content) - content="--$delim${nl}" if [ -z "$ssl_uuid" ]; then #set sni to domain - content="$content{nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain" + content="--$delim${nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain" fi #add key content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" @@ -67,7 +63,7 @@ kong_deploy() { _debug content "$content" #Check if sslcreated (if not => POST else => PATCH) - if [ ! -z "$ssl_uuid" ]; then + if [ -z "$ssl_uuid" ]; then #Post certificate to Kong response=$(_post "$content" "$KONG_URL/certificates" "" "POST") else From 148f869becd09518d015881763ab3f2ba98bfa2c Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 27 Apr 2017 22:21:59 +0800 Subject: [PATCH 351/620] fix https://github.com/Neilpang/acme.sh/issues/805 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 3506bdb9..56e1ea49 100755 --- a/acme.sh +++ b/acme.sh @@ -1108,7 +1108,7 @@ _readKeyLengthFromCSR() { echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' else _debug "RSA CSR" - echo "$_outcsr" | tr "\t" " " | _egrep_o "(^ *|RSA )Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 + echo "$_outcsr" | tr "\t" " " | (_egrep_o "^ *Public.Key:.*" || _egrep_o "RSA Public.Key:.*") | cut -d '(' -f 2 | cut -d ' ' -f 1 fi } From 824ffa24f497a69bd4b0cb0cf10520b27d326514 Mon Sep 17 00:00:00 2001 From: Andre Cantero Date: Fri, 28 Apr 2017 00:21:21 +0800 Subject: [PATCH 352/620] Add shebang --- deploy/kong.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/kong.sh b/deploy/kong.sh index 9d1f40a7..dce92096 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -1,3 +1,4 @@ +#!/usr/bin/env sh # Note that ssl plugin should be available on Kong instance # The hook will match cdomain to request_host, in case of multiple domain it will always take the first # one (acme.sh behaviour). From 1231b71245588f107bc9667c16925afeac0f4e4e Mon Sep 17 00:00:00 2001 From: Andre Cantero Date: Fri, 28 Apr 2017 00:25:30 +0800 Subject: [PATCH 353/620] Update the notes --- deploy/kong.sh | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/deploy/kong.sh b/deploy/kong.sh index dce92096..d3a6bc47 100755 --- a/deploy/kong.sh +++ b/deploy/kong.sh @@ -1,11 +1,7 @@ #!/usr/bin/env sh -# Note that ssl plugin should be available on Kong instance -# The hook will match cdomain to request_host, in case of multiple domain it will always take the first -# one (acme.sh behaviour). -# If ssl config already exist it will update only cert and key not touching other parameter -# If ssl config doesn't exist it will only upload cert and key and not set other parameter -# Not that we deploy full chain -# See https://getkong.org/plugins/dynamic-ssl/ for other options +# If certificate already exist it will update only cert and key not touching other parameter +# If certificate doesn't exist it will only upload cert and key and not set other parameter +# Note that we deploy full chain # Written by Geoffroi Genot ######## Public functions ##################### From 5b3e3d9cf444e3c9e969244baedc18338f5b4ccc Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 30 Apr 2017 16:29:20 +0800 Subject: [PATCH 354/620] fix https://github.com/Neilpang/acme.sh/issues/812 --- acme.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 3506bdb9..7ce947ea 100755 --- a/acme.sh +++ b/acme.sh @@ -166,7 +166,14 @@ _syslog() { fi _logclass="$1" shift - logger -i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1 + if [ -z "$__logger_i" ]; then + if _contains "$(logger --help 2>&1)" "-i"; then + __logger_i="logger -i" + else + __logger_i="logger" + fi + fi + $__logger_i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1 } _log() { From 2310a9bbc0d043cc3340af8a933a0679004874ae Mon Sep 17 00:00:00 2001 From: shar0119 Date: Sun, 30 Apr 2017 10:32:56 -0700 Subject: [PATCH 355/620] Removed grep -Po Removed usage of grep -Po. --- dnsapi/dns_dynu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index 19e7fc7b..f6eabde2 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -149,7 +149,7 @@ _get_recordid() { return 0 fi - _dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | grep -Po '"id":\K[0-9]+') + _dns_record_id=$(printf "%s" "$response" | _egrep_o "{[^}]*}" | grep "\"text_data\":\"$txtvalue\"" | _egrep_o ",[^,]*," | grep ',"id":' | tr -d ",," | cut -d : -f 2) return 0 } From f5c381d5b466094f7c26573341deb517df5456b9 Mon Sep 17 00:00:00 2001 From: ka2er Date: Tue, 2 May 2017 00:45:29 +0200 Subject: [PATCH 356/620] less permissive permission on OVH API restrict authorization request to OVH /domain API and not whole OVH API. Not perfect due to some limitations in regex with *, but better security as the token don't give full access to the API. --- dnsapi/dns_ovh.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh index 18f9c7dc..6c1edb4d 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -119,7 +119,7 @@ dns_ovh_add() { _info "Checking authentication" - response="$(_ovh_rest GET "domain/")" + response="$(_ovh_rest GET "domain")" if _contains "$response" "INVALID_CREDENTIAL"; then _err "The consumer key is invalid: $OVH_CK" _err "Please retry to create a new one." @@ -191,7 +191,7 @@ _ovh_authentication() { _H3="" _H4="" - _ovhdata='{"accessRules": [{"method": "GET","path": "/*"},{"method": "POST","path": "/*"},{"method": "PUT","path": "/*"},{"method": "DELETE","path": "/*"}],"redirection":"'$ovh_success'"}' + _ovhdata='{"accessRules": [{"method": "GET","path": "/auth/time"},{"method": "GET","path": "/domain"},{"method": "GET","path": "/domain/zone/*"},{"method": "GET","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/refresh"},{"method": "PUT","path": "/domain/zone/*/record/*"}],"redirection":"'$ovh_success'"}' response="$(_post "$_ovhdata" "$OVH_API/auth/credential")" _debug3 response "$response" From 1994c6828ecaaefa50beb8fb5616ed51a3b98c48 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Mon, 5 Dec 2016 21:53:02 -0600 Subject: [PATCH 357/620] include dnsimple api Even though DNSimple is technically covered with lexicon not all systems can install python pip's easily. For these systems it is useful to have pure shell script API interactions. --- README.md | 1 + dnsapi/README.md | 36 +++++++-- dnsapi/dns_dnsimple.sh | 163 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 dnsapi/dns_dnsimple.sh diff --git a/README.md b/README.md index 0a320369..34b9243a 100644 --- a/README.md +++ b/README.md @@ -292,6 +292,7 @@ You don't have to do anything manually! 1. CloudFlare.com API 1. DNSPod.cn API +1. DNSimple API 1. CloudXNS.com API 1. GoDaddy.com API 1. OVH, kimsufi, soyoustart and runabove API diff --git a/dnsapi/README.md b/dnsapi/README.md index 12d76bef..ad03ea79 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -422,31 +422,31 @@ acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com ``` ## 22. Use Infoblox API - + First you need to create/obtain API credentials on your Infoblox appliance. - + ``` export Infoblox_Creds="username:password" export Infoblox_Server="ip or fqdn of infoblox appliance" ``` - + Ok, let's issue a cert now: ``` acme.sh --issue --dns dns_infoblox -d example.com -d www.example.com ``` - + Note: This script will automatically create and delete the ephemeral txt record. The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. ## 23. Use VSCALE API - + First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). - + ``` VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" ``` - + Ok, let's issue a cert now: ``` acme.sh --issue --dns dns_vscale -d example.com -d www.example.com @@ -468,6 +468,28 @@ 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. # Use custom API diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh new file mode 100644 index 00000000..d714d36c --- /dev/null +++ b/dnsapi/dns_dnsimple.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env sh + +# DNSimple domain api +# +# This is your oauth token which can be acquired on the account page. Please +# note that this must be an _account_ token and not a _user_ token. +# https://dnsimple.com/a//account/access_tokens +# DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje" + +DNSimple_API="https://api.dnsimple.com/v2" + +######## Public functions ##################### + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_dnsimple_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$DNSimple_OAUTH_TOKEN" ]; then + DNSimple_OAUTH_TOKEN="" + _err "You have not set the dnsimple oauth token yet." + _err "Please visit https://dnsimple.com/user to generate it." + return 1 + fi + + # save the oauth token for later + _saveaccountconf DNSimple_OAUTH_TOKEN "$DNSimple_OAUTH_TOKEN" + + _debug "Retrive account ID" + if ! _get_account_id; then + _err "failed to retrive account id" + return 1 + fi + _debug _account_id "$_account_id" + + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain "$_domain" + _debug _sub_domain "$_sub_domain" + + _debug "Getting txt records" + _dnsimple_rest GET "$_account_id/zones/$_domain/records?per_page=100" + + if ! _contains "$response" "\"id\":"; then + _err "Error" + return 1 + fi + + count=$(printf "%s" "$response" | _egrep_o "\"name\":\"$_sub_domain\"" | wc -l | _egrep_o "[0-9]+") + _debug count "$count" + + if [ "$count" = "0" ]; then + _info "Adding record" + if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then + if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then + _info "Added" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + record_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"zone_id\":\"[^,]*\",\"parent_id\":null,\"name\":\"$_sub_domain\"" | cut -d: -f2 | cut -d, -f1) + _debug "record_id" "$record_id" + + _dnsimple_rest PATCH "$_account_id/zones/$_domain/records/$record_id" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}" + if [ "$?" = "0" ]; then + _info "Updated!" + #todo: check if the record takes effect + return 0 + fi + _err "Update error" + return 1 + fi +} + +# fulldomain +dns_dnsimple_rm() { + fulldomain=$1 + +} + +#################### Private functions bellow ################################## +# _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 ! _dnsimple_rest GET "$_account_id/zones/$h"; then + return 1 + fi + + if _contains "$response" 'not found'; then + _debug "$h not found" + else + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +_get_account_id() { + if ! _dnsimple_rest GET "whoami"; then + return 1 + fi + + if _contains "$response" "\"account\":null"; then + _err "no account associated with this token" + return 1 + fi + + if _contains "$response" "timeout"; then + _err "timeout retrieving account_id" + return 1 + fi + + _account_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"email\":" | cut -d: -f2 | cut -d, -f1) + return 0 +} + +_dnsimple_rest() { + method=$1 + path="$2" + data="$3" + request_url="$DNSimple_API/$path" + _debug "$path" + + _H1="Accept: application/json" + _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" + if [ "$data" ]; then + _H1="Content-Type: application/json" + _debug data "$data" + response="$(_post "$data" "$request_url" "" "$method")" + else + response="$(_get "$request_url")" + fi + + if [ "$?" != "0" ]; then + _err "error $request_url" + return 1 + fi + _debug2 response "$response" + return 0 +} From 2b092539618fc4ca627f9aa2b7b021488e222397 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Tue, 6 Dec 2016 08:32:14 -0600 Subject: [PATCH 358/620] link to contributor repo for support issues relating to the dnsimple API integration --- dnsapi/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index ad03ea79..f53d8ad4 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -491,6 +491,9 @@ 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. + # Use custom API If your API is not supported yet, you can write your own DNS API. From f4e81953ce59731c3c46f7dc6937417851bd6e88 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Sun, 12 Feb 2017 16:07:05 -0600 Subject: [PATCH 359/620] provide a more general purpose request function This allows for more flexibility in the future. Most importantly being able to do more than just GET requests but any HTTP method. Specifically needed for DELETE requests. --- acme.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 7ce947ea..3ccd8dc4 100755 --- a/acme.sh +++ b/acme.sh @@ -1592,12 +1592,17 @@ _post() { return $_ret } -# url getheader timeout _get() { - _debug GET + _request "$1" "$2" "$3" GET +} + +# url getheader timeout +_request() { url="$1" onlyheader="$2" t="$3" + method="$4" + _debug method $method _debug url "$url" _debug "timeout" "$t" @@ -1611,6 +1616,9 @@ _get() { if [ "$t" ]; then _CURL="$_CURL --connect-timeout $t" fi + if [ "$method" ]; then + _CURL="$_CURL -X $method" + fi _debug "_CURL" "$_CURL" if [ "$onlyheader" ]; then $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" @@ -1633,6 +1641,9 @@ _get() { if [ "$t" ]; then _WGET="$_WGET --timeout=$t" fi + if [ "$method" ]; then + _WGET="$_WGET --method=$method" + fi _debug "_WGET" "$_WGET" if [ "$onlyheader" ]; then $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null "$url" 2>&1 | sed 's/^[ ]*//g' From f9b419d1e40c6056675891e846841158f36dc01a Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Sun, 12 Feb 2017 16:08:32 -0600 Subject: [PATCH 360/620] cleanup dns in dnsimple api integration Implement the `_rm()` method for the DNSimple integration. This also required some changes and cleanup to DRY up the code. --- dnsapi/dns_dnsimple.sh | 96 +++++++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 24 deletions(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index d714d36c..dde6638e 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -26,49 +26,35 @@ dns_dnsimple_add() { # save the oauth token for later _saveaccountconf DNSimple_OAUTH_TOKEN "$DNSimple_OAUTH_TOKEN" - _debug "Retrive account ID" if ! _get_account_id; then _err "failed to retrive account id" return 1 fi - _debug _account_id "$_account_id" if ! _get_root "$fulldomain"; then _err "invalid domain" return 1 fi - _debug _domain "$_domain" - _debug _sub_domain "$_sub_domain" - - _debug "Getting txt records" - _dnsimple_rest GET "$_account_id/zones/$_domain/records?per_page=100" - - if ! _contains "$response" "\"id\":"; then - _err "Error" - return 1 - fi - count=$(printf "%s" "$response" | _egrep_o "\"name\":\"$_sub_domain\"" | wc -l | _egrep_o "[0-9]+") - _debug count "$count" + _get_records $_account_id $_domain $_sub_domain - if [ "$count" = "0" ]; then + if [ "$_records_count" = "0" ]; then _info "Adding record" if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then _info "Added" return 0 else - _err "Add txt record error." + _err "Unexpected response while adding text record." return 1 fi fi _err "Add txt record error." else _info "Updating record" - record_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"zone_id\":\"[^,]*\",\"parent_id\":null,\"name\":\"$_sub_domain\"" | cut -d: -f2 | cut -d, -f1) - _debug "record_id" "$record_id" + _extract_record_id $_records $_sub_domain - _dnsimple_rest PATCH "$_account_id/zones/$_domain/records/$record_id" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}" + _dnsimple_rest PATCH "$_account_id/zones/$_domain/records/$_record_id" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}" if [ "$?" = "0" ]; then _info "Updated!" #todo: check if the record takes effect @@ -83,6 +69,31 @@ dns_dnsimple_add() { dns_dnsimple_rm() { fulldomain=$1 + if ! _get_account_id; then + _err "failed to retrive account id" + return 1 + fi + + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _get_records $_account_id $_domain $_sub_domain + _extract_record_id $_records $_sub_domain + + if [ "$_record_id" ]; then + _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id" + + if [ "$?" = "0" ]; then + _info "removed record" "$_record_id" + return 0 + fi + fi + + _err "failed to remove record" "$_record_id" + return 1 + } #################### Private functions bellow ################################## @@ -93,7 +104,7 @@ dns_dnsimple_rm() { _get_root() { domain=$1 i=2 - p=1 + previous=1 while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) if [ -z "$h" ]; then @@ -108,17 +119,24 @@ _get_root() { if _contains "$response" 'not found'; then _debug "$h not found" else - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$previous) _domain="$h" + + _debug _domain "$_domain" + _debug _sub_domain "$_sub_domain" + return 0 fi - p="$i" + + previous="$i" i=$(_math "$i" + 1) done return 1 } +# returns _account_id _get_account_id() { + _debug "retrive account id" if ! _dnsimple_rest GET "whoami"; then return 1 fi @@ -129,14 +147,44 @@ _get_account_id() { fi if _contains "$response" "timeout"; then - _err "timeout retrieving account_id" + _err "timeout retrieving account id" return 1 fi _account_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"email\":" | cut -d: -f2 | cut -d, -f1) + _debug _account_id "$_account_id" + return 0 } +# returns +# _records +# _records_count +_get_records() { + account_id=$1 + domain=$2 + sub_domain=$3 + + _debug "fetching txt records" + _dnsimple_rest GET "$account_id/zones/$domain/records?per_page=100" + + if ! _contains "$response" "\"id\":"; then + _err "failed to retrieve records" + return 1 + fi + + _records_count=$(printf "%s" "$response" | _egrep_o "\"name\":\"$sub_domain\"" | wc -l | _egrep_o "[0-9]+") + _records=$response + _debug _records_count "$_records_count" +} + +# returns _record_id +_extract_record_id() { + _record_id=$(printf "%s" "$_records" | _egrep_o "\"id\":[^,]*,\"zone_id\":\"[^,]*\",\"parent_id\":null,\"name\":\"$_sub_domain\"" | cut -d: -f2 | cut -d, -f1) + _debug "_record_id" "$_record_id" +} + +# returns response _dnsimple_rest() { method=$1 path="$2" @@ -151,7 +199,7 @@ _dnsimple_rest() { _debug data "$data" response="$(_post "$data" "$request_url" "" "$method")" else - response="$(_get "$request_url")" + response="$(_request "$request_url" "" "" "$method")" fi if [ "$?" != "0" ]; then From 326ac485b35e2783365f5ab660caec28fc64d794 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Sun, 12 Feb 2017 16:15:37 -0600 Subject: [PATCH 361/620] link to repo for dnsimple integration support --- dnsapi/dns_dnsimple.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index dde6638e..f1c841dc 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -1,6 +1,7 @@ #!/usr/bin/env sh # DNSimple domain api +# https://github.com/pho3nixf1re/acme.sh/issues # # This is your oauth token which can be acquired on the account page. Please # note that this must be an _account_ token and not a _user_ token. From 2f4111a2e2ed01c27e070b375fa3f0179d0b46d3 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Mon, 13 Feb 2017 11:37:34 -0600 Subject: [PATCH 362/620] fixup shellcheck style issues --- dnsapi/dns_dnsimple.sh | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index f1c841dc..d92c6137 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -37,7 +37,7 @@ dns_dnsimple_add() { return 1 fi - _get_records $_account_id $_domain $_sub_domain + _get_records "$_account_id" "$_domain" "$_sub_domain" if [ "$_records_count" = "0" ]; then _info "Adding record" @@ -53,14 +53,17 @@ dns_dnsimple_add() { _err "Add txt record error." else _info "Updating record" - _extract_record_id $_records $_sub_domain + _extract_record_id "$_records" "$_sub_domain" + + if _dnsimple_rest \ + PATCH \ + "$_account_id/zones/$_domain/records/$_record_id" \ + "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - _dnsimple_rest PATCH "$_account_id/zones/$_domain/records/$_record_id" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}" - if [ "$?" = "0" ]; then _info "Updated!" - #todo: check if the record takes effect return 0 fi + _err "Update error" return 1 fi @@ -80,13 +83,12 @@ dns_dnsimple_rm() { return 1 fi - _get_records $_account_id $_domain $_sub_domain - _extract_record_id $_records $_sub_domain + _get_records "$_account_id" "$_domain" "$_sub_domain" + _extract_record_id "$_records" "$_sub_domain" if [ "$_record_id" ]; then - _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id" - if [ "$?" = "0" ]; then + if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id"; then _info "removed record" "$_record_id" return 0 fi @@ -193,8 +195,9 @@ _dnsimple_rest() { request_url="$DNSimple_API/$path" _debug "$path" - _H1="Accept: application/json" - _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" + export _H1="Accept: application/json" + export _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" + if [ "$data" ]; then _H1="Content-Type: application/json" _debug data "$data" From 5b21cbe0de81f858e29a5abf3e3c0c35ae6a18d3 Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Mon, 1 May 2017 20:56:04 -0500 Subject: [PATCH 363/620] Revert "provide a more general purpose request function" This reverts commit aa86652db8d3132fb7fe0c0253dded7deb7dce2c. This is not actually necessary and can be accomplished with the post function. --- acme.sh | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/acme.sh b/acme.sh index 3ccd8dc4..7ce947ea 100755 --- a/acme.sh +++ b/acme.sh @@ -1592,17 +1592,12 @@ _post() { return $_ret } -_get() { - _request "$1" "$2" "$3" GET -} - # url getheader timeout -_request() { +_get() { + _debug GET url="$1" onlyheader="$2" t="$3" - method="$4" - _debug method $method _debug url "$url" _debug "timeout" "$t" @@ -1616,9 +1611,6 @@ _request() { if [ "$t" ]; then _CURL="$_CURL --connect-timeout $t" fi - if [ "$method" ]; then - _CURL="$_CURL -X $method" - fi _debug "_CURL" "$_CURL" if [ "$onlyheader" ]; then $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" @@ -1641,9 +1633,6 @@ _request() { if [ "$t" ]; then _WGET="$_WGET --timeout=$t" fi - if [ "$method" ]; then - _WGET="$_WGET --method=$method" - fi _debug "_WGET" "$_WGET" if [ "$onlyheader" ]; then $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null "$url" 2>&1 | sed 's/^[ ]*//g' From 533238712536e3a11c2b09b4d0d480891cfd3d9f Mon Sep 17 00:00:00 2001 From: Matthew Turney Date: Tue, 2 May 2017 08:51:43 -0500 Subject: [PATCH 364/620] Use _post to send a DELETE request for DNSimple record removal. --- dnsapi/dns_dnsimple.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_dnsimple.sh b/dnsapi/dns_dnsimple.sh index d92c6137..0bfe2b99 100644 --- a/dnsapi/dns_dnsimple.sh +++ b/dnsapi/dns_dnsimple.sh @@ -198,12 +198,12 @@ _dnsimple_rest() { export _H1="Accept: application/json" export _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" - if [ "$data" ]; then + if [ "$data" ] || [ "$method" = "DELETE" ]; then _H1="Content-Type: application/json" _debug data "$data" response="$(_post "$data" "$request_url" "" "$method")" else - response="$(_request "$request_url" "" "" "$method")" + response="$(_get "$request_url" "" "" "$method")" fi if [ "$?" != "0" ]; then From 4c38fec3b57e23d5aece5dfd92ac1f50abc6b150 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 3 May 2017 23:07:30 +0800 Subject: [PATCH 365/620] update doc --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 34b9243a..0cb800eb 100644 --- a/README.md +++ b/README.md @@ -136,13 +136,25 @@ root@v1:~# acme.sh -h acme.sh --issue -d example.com -w /home/wwwroot/example.com ``` +or: + +```bash +acme.sh --issue -d example.com -w /home/username/public_html +``` + +or: + +```bash +acme.sh --issue -d example.com -w /var/www/html +``` + **Example 2:** Multiple domains in the same cert. ```bash acme.sh --issue -d example.com -d www.example.com -d cp.example.com -w /home/wwwroot/example.com ``` -The parameter `/home/wwwroot/example.com` is the web root folder. You **MUST** have `write access` to this folder. +The parameter `/home/wwwroot/example.com` or `/home/username/public_html` or `/var/www/html` is the web root folder where you host your website files. You **MUST** have `write access` to this folder. Second argument **"example.com"** is the main domain you want to issue the cert for. You must have at least one domain there. From cc1d3b20b60a9f729bbd0f61f6563d2fe34772d4 Mon Sep 17 00:00:00 2001 From: wizard1024 Date: Fri, 5 May 2017 14:55:51 +0300 Subject: [PATCH 366/620] Update dns_aws.sh to work only with public zones --- 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 21e86686..800c3d09 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -106,7 +106,7 @@ _get_root() { fi if _contains "$response" "$h."; then - hostedzone="$(echo "$response" | sed 's//#&/g' | tr '#' '\n' | _egrep_o "[^<]*<.Id>$h.<.Name>.*<.HostedZone>")" + hostedzone="$(echo "$response" | sed 's//#&/g' | tr '#' '\n' | _egrep_o "[^<]*<.Id>$h.<.Name>.*false<.PrivateZone>.*<.HostedZone>")" _debug hostedzone "$hostedzone" if [ -z "$hostedzone" ]; then _err "Error, can not get hostedzone." From 5e3a5f627a94efea26d18d7eebb022a99a6149dd Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 8 May 2017 15:51:01 +0200 Subject: [PATCH 367/620] last but not least --- README.md | 1 + dnsapi/README.md | 11 +++ dnsapi/dns_nsone.sh | 158 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 dnsapi/dns_nsone.sh diff --git a/README.md b/README.md index 0cb800eb..b816ec7f 100644 --- a/README.md +++ b/README.md @@ -329,6 +329,7 @@ You don't have to do anything manually! 1. Infoblox NIOS API (https://www.infoblox.com/) 1. VSCALE (https://vscale.io/) 1. Dynu API (https://www.dynu.com) +1. NS1.com API **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index f53d8ad4..dff62399 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -494,6 +494,17 @@ 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 +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh new file mode 100644 index 00000000..48e4397f --- /dev/null +++ b/dnsapi/dns_nsone.sh @@ -0,0 +1,158 @@ +#!/bin/bash + +# bug reports to dev@1e.ca + +# +#NS1_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# + +NS1_Api="https://api.nsone.net/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_nsone_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$NS1_Key" ]; then + NS1_Key="" + _err "You didn't specify nsone dns api key yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf NS1_Key "$NS1_Key" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _nsone_rest GET "zones/${_domain}" + + if ! _contains "$response" "\"records\":"; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Adding record" + + if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\"}"; then + if _contains "$response" "$fulldomain"; then + _info "Added" + #todo: check if the record takes effect + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + record_id=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\",\"id\":\"[^,]*\"" | _head_n 1 | cut -d: -f7 | cut -d, -f1) + _debug "record_id" "$record_id" + + _nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}" + if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then + _info "Updated!" + #todo: check if the record takes effect + return 0 + fi + _err "Update error" + return 1 + fi + +} + +#fulldomain +dns_nsone_rm() { + fulldomain=$1 + txtvalue=$2 + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _nsone_rest GET "zones/${_domain}/$fulldomain/TXT" + + count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",.*\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + if ! _nsone_rest DELETE "zones/${_domain}/$fulldomain/TXT"; then + _err "Delete record error." + return 1 + fi + _contains "$response" "" + fi +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + if ! _nsone_rest GET "zones"; then + return 1 + fi + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "\"zone\":\"$h\""; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_nsone_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Accept: application/json" + export _H2="X-NSONE-Key: $NS1_Key" + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$NS1_Api/$ep" "" "$m")" + else + response="$(_get "$NS1_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From dff641a665bffab928ebf0121ff15e86a608de96 Mon Sep 17 00:00:00 2001 From: nytral Date: Mon, 8 May 2017 16:07:45 +0200 Subject: [PATCH 368/620] I can do it... just discovered vmdiff --- README.md | 1 - dnsapi/README.md | 5 +---- dnsapi/dns_nsone.sh | 2 -- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/README.md b/README.md index a67a9061..b816ec7f 100644 --- a/README.md +++ b/README.md @@ -324,7 +324,6 @@ You don't have to do anything manually! 1. Domain-Offensive/Resellerinterface/Domainrobot API 1. Gandi LiveDNS API 1. Knot DNS API -1. NS1.com API 1. DigitalOcean API (native) 1. ClouDNS.net API 1. Infoblox NIOS API (https://www.infoblox.com/) diff --git a/dnsapi/README.md b/dnsapi/README.md index 25ba1c34..dff62399 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -494,8 +494,7 @@ be reused when needed. If you have any issues with this integration please report them to https://github.com/pho3nixf1re/acme.sh/issues. -<<<<<<< HEAD -## 28. Use NS1.com API +## 26. Use NS1.com API ``` export NS1_Key="fdmlfsdklmfdkmqsdfk" @@ -505,8 +504,6 @@ Ok, let's issue a cert now: ``` acme.sh --issue --dns dns_nsone -d example.com -d www.example.com ``` -======= ->>>>>>> 9201e0a5b905812da1157efa075dd1ab52362c09 # Use custom API diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index ced65ac0..0f6e441a 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -1,6 +1,4 @@ -<<<<<<< HEAD #!/usr/bin/env sh ->>>>>>> 9201e0a5b905812da1157efa075dd1ab52362c09 # bug reports to dev@1e.ca From 9bc5f686ebb7e866bb8d0bf7299989d86a1c8d63 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 8 May 2017 22:25:06 +0800 Subject: [PATCH 369/620] fix list order --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b816ec7f..7e6b1227 100644 --- a/README.md +++ b/README.md @@ -304,17 +304,14 @@ You don't have to do anything manually! 1. CloudFlare.com API 1. DNSPod.cn API -1. DNSimple API 1. CloudXNS.com API 1. GoDaddy.com API -1. OVH, kimsufi, soyoustart and runabove API -1. AWS Route 53 1. PowerDNS.com API -1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api - (DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.) +1. OVH, kimsufi, soyoustart and runabove API +1. nsupdate API 1. LuaDNS.com API 1. DNSMadeEasy.com API -1. nsupdate API +1. AWS Route 53 1. aliyun.com(阿里云) API 1. ISPConfig 3.1 API 1. Alwaysdata.com API @@ -329,9 +326,18 @@ You don't have to do anything manually! 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 + +And: + +1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api + (DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.) + + + **More APIs coming soon...** 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. From 5da1d3b73bdbec8fb5db9283d2755106c23847e0 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 8 May 2017 22:55:21 +0800 Subject: [PATCH 370/620] minor fix format --- dnsapi/dns_nsone.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index 0f6e441a..7af0f81d 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -45,7 +45,7 @@ dns_nsone_add() { _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" - + if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\"}"; then if _contains "$response" "$fulldomain"; then _info "Added" @@ -124,9 +124,9 @@ _get_root() { fi if _contains "$response" "\"zone\":\"$h\""; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - _domain="$h" - return 0 + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 fi p=$i i=$(_math "$i" + 1) From a20707cd731f98b820f56dbd92bad0477c91ea1c Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 8 May 2017 22:57:23 +0800 Subject: [PATCH 371/620] fix format --- dnsapi/dns_nsone.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh index 7af0f81d..adf1f422 100644 --- a/dnsapi/dns_nsone.sh +++ b/dnsapi/dns_nsone.sh @@ -45,7 +45,7 @@ dns_nsone_add() { _debug count "$count" if [ "$count" = "0" ]; then _info "Adding record" - + if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\"}"; then if _contains "$response" "$fulldomain"; then _info "Added" From 0f48b15695d5c04e98e6a36d7c59dcc47ebe1666 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 9 May 2017 13:33:54 +0800 Subject: [PATCH 372/620] update doc --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7e6b1227..a163f233 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ - Just one script to issue, renew and install your certificates automatically. - DOES NOT require `root/sudoer` access. - Docker friendly +- IPv6 support It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. From c487cd6af2067bbfee9d66465503cdac9bbbb102 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 11 May 2017 20:51:16 +0800 Subject: [PATCH 373/620] add VOLUME --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index feb89b0d..3b262615 100644 --- a/Dockerfile +++ b/Dockerfile @@ -55,5 +55,7 @@ else \n \ /root/.acme.sh/acme.sh --config-home /acme.sh \"\$@\"\n \ fi" >/entry.sh && chmod +x /entry.sh +VOLUME /acme.sh + ENTRYPOINT ["/entry.sh"] CMD ["--help"] From d61ef6b49ae442b93b36aba67ba6037a0a5948d1 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 12 May 2017 11:27:06 +0800 Subject: [PATCH 374/620] gandi dns api updated. --- dnsapi/dns_gandi_livedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 28b8f99d..82ed599c 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -37,7 +37,7 @@ dns_gandi_livedns_add() { _debug sub_domain "$_sub_domain" _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \ - && _contains "$response" '{"message": "Zone Record Created"}' \ + && _contains "$response" '{"message": "DNS Record Created"}' \ && _info "Add $(__green "success")" } From 319d49ddbe81a7d72009f203e1a56f1c6e614742 Mon Sep 17 00:00:00 2001 From: The Gitter Badger Date: Fri, 12 May 2017 05:37:15 +0000 Subject: [PATCH 375/620] Add Gitter badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a163f233..afdda8a8 100644 --- a/README.md +++ b/README.md @@ -1,4 +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) - An ACME protocol client written purely in Shell (Unix shell) language. - Full ACME protocol implementation. - Simple, powerful and very easy to use. You only need 3 minutes to learn it. From df037db0bb804eb05352974b66dfd564fff7608c Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 14 May 2017 10:15:40 +0800 Subject: [PATCH 376/620] clean cache --- Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3b262615..4cb33139 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,17 +4,17 @@ RUN apk update -f \ && apk --no-cache add -f \ openssl \ curl \ - netcat-openbsd + netcat-openbsd \ + && rm -rf /var/cache/apk/* ENV LE_CONFIG_HOME /acme.sh ENV AUTO_UPGRADE 1 #Install -RUN mkdir -p /install_acme.sh/ ADD ./ /install_acme.sh/ -RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) -RUN rm -rf /install_acme.sh/ +RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/ + RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh From 2844d73dc752138c48c7ec05a93869d931782ff5 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 15 May 2017 20:46:02 +0800 Subject: [PATCH 377/620] fix https://github.com/Neilpang/acme.sh/issues/844 --- acme.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/acme.sh b/acme.sh index 7ce947ea..77be3fd5 100755 --- a/acme.sh +++ b/acme.sh @@ -1244,17 +1244,20 @@ createDomainKey() { fi domain=$1 - length=$2 + _cdl=$2 - if [ -z "$length" ]; then + if [ -z "$_cdl" ]; then _debug "Use DEFAULT_DOMAIN_KEY_LENGTH=$DEFAULT_DOMAIN_KEY_LENGTH" - length="$DEFAULT_DOMAIN_KEY_LENGTH" + _cdl="$DEFAULT_DOMAIN_KEY_LENGTH" fi - _initpath "$domain" "$length" + _initpath "$domain" "$_cdl" if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]); then - _createkey "$length" "$CERT_KEY_PATH" + if _createkey "$_cdl" "$CERT_KEY_PATH"; then + _savedomainconf Le_Keylength "$_cdl" + _info "The domain key is here: $(__green $CERT_KEY_PATH)" + fi else if [ "$IS_RENEW" ]; then _info "Domain key exists, skip" From b420ec6cb96f625e400fccfe60c3ad6256f03c32 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 17 May 2017 13:16:53 +0800 Subject: [PATCH 378/620] fix for performance of _h2b() function --- acme.sh | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/acme.sh b/acme.sh index 77be3fd5..8edf2c61 100755 --- a/acme.sh +++ b/acme.sh @@ -444,19 +444,27 @@ if [ "$(printf '\x41')" != 'A' ]; then fi _h2b() { + if _exists xxd; then + xxd -r -p + return + fi + hex=$(cat) i=1 j=2 - - _debug3 _URGLY_PRINTF "$_URGLY_PRINTF" - while true; do - if [ -z "$_URGLY_PRINTF" ]; then + _debug2 _URGLY_PRINTF "$_URGLY_PRINTF" + if [ -z "$_URGLY_PRINTF" ]; then + while true; do h="$(printf "%s" "$hex" | cut -c $i-$j)" if [ -z "$h" ]; then break fi printf "\x$h%s" - else + i="$(_math "$i" + 2)" + j="$(_math "$j" + 2)" + done + else + while true; do ic="$(printf "%s" "$hex" | cut -c $i)" jc="$(printf "%s" "$hex" | cut -c $j)" if [ -z "$ic$jc" ]; then @@ -465,12 +473,11 @@ _h2b() { ic="$(_h_char_2_dec "$ic")" jc="$(_h_char_2_dec "$jc")" printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s" - fi - - i="$(_math "$i" + 2)" - j="$(_math "$j" + 2)" + i="$(_math "$i" + 2)" + j="$(_math "$j" + 2)" + done + fi - done } _is_solaris() { From fa93d68b085dd5cef9f09fba8de665b31d0a5665 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 20 May 2017 11:02:48 +0800 Subject: [PATCH 379/620] promote performance --- acme.sh | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/acme.sh b/acme.sh index 8edf2c61..17062806 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.6.9 +VER=2.7.0 PROJECT_NAME="acme.sh" @@ -450,31 +450,35 @@ _h2b() { fi hex=$(cat) - i=1 - j=2 + ic="" + jc="" _debug2 _URGLY_PRINTF "$_URGLY_PRINTF" if [ -z "$_URGLY_PRINTF" ]; then - while true; do - h="$(printf "%s" "$hex" | cut -c $i-$j)" - if [ -z "$h" ]; then - break - fi - printf "\x$h%s" - i="$(_math "$i" + 2)" - j="$(_math "$j" + 2)" - done + if _exists xargs; then + _debug2 "xargs" + echo "$hex" | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf + else + for h in $(echo "$hex" | sed 's/\([0-9A-F]\{2\}\)/ \1/gI') + do + if [ -z "$h" ]; then + break + fi + printf "\x$h%s" + done + fi else - while true; do - ic="$(printf "%s" "$hex" | cut -c $i)" - jc="$(printf "%s" "$hex" | cut -c $j)" - if [ -z "$ic$jc" ]; then - break + for c in $(echo "$hex" | sed 's/\([0-9A-F]\)/ \1/gI') + do + if [ -z "$ic" ]; then + ic=$c + continue fi + jc=$c ic="$(_h_char_2_dec "$ic")" jc="$(_h_char_2_dec "$jc")" printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s" - i="$(_math "$i" + 2)" - j="$(_math "$j" + 2)" + ic="" + jc="" done fi From ed3dda7da960072f48370a25dd5beaccb7302cf2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 20 May 2017 11:15:26 +0800 Subject: [PATCH 380/620] fix format --- acme.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 17062806..f255c43f 100755 --- a/acme.sh +++ b/acme.sh @@ -458,8 +458,7 @@ _h2b() { _debug2 "xargs" echo "$hex" | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf else - for h in $(echo "$hex" | sed 's/\([0-9A-F]\{2\}\)/ \1/gI') - do + for h in $(echo "$hex" | sed 's/\([0-9A-F]\{2\}\)/ \1/gI'); do if [ -z "$h" ]; then break fi @@ -467,8 +466,7 @@ _h2b() { done fi else - for c in $(echo "$hex" | sed 's/\([0-9A-F]\)/ \1/gI') - do + for c in $(echo "$hex" | sed 's/\([0-9A-F]\)/ \1/gI'); do if [ -z "$ic" ]; then ic=$c continue From 486e77f474d1da05bc9201a7446b12dc4abc38b4 Mon Sep 17 00:00:00 2001 From: Jean-Tiare Le Bigot Date: Mon, 22 May 2017 14:13:39 +0200 Subject: [PATCH 381/620] Support OVH credentials scoped to a specific zone When creating OVH API credentials, one can scope them to a specific subset of routes. Specifically, this allows to limit acme.sh to a specific zone as the zone is part of the URL. This is an important security/safety net feature. --- 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 6c1edb4d..eaa90bdf 100755 --- a/dnsapi/dns_ovh.sh +++ b/dnsapi/dns_ovh.sh @@ -238,7 +238,7 @@ _get_root() { return 1 fi - if ! _contains "$response" "This service does not exist" >/dev/null; then + if ! _contains "$response" "This service does not exist" >/dev/null && ! _contains "$response" "NOT_GRANTED_CALL" >/dev/null; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) _domain="$h" return 0 From 7eea9533e895f405d2fbbbb110a42d8f74967127 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Mon, 22 May 2017 14:53:26 -0500 Subject: [PATCH 382/620] Update README.md Fix usage documentation for dns_nsupdate. The NSUPDATE_KEY env needs to be a path to a file. --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index dff62399..5dca829a 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -140,7 +140,7 @@ Finally, make the DNS server and update Key available to `acme.sh` ``` export NSUPDATE_SERVER="dns.example.com" -export NSUPDATE_KEY="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa==" +export NSUPDATE_KEY="/path/to/your/nsupdate.key" ``` Ok, let's issue a cert now: From aa66dfff57b17e1fe1d37f1389be5a768a85116e Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 25 May 2017 21:06:59 +0800 Subject: [PATCH 383/620] fix doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index afdda8a8..8ddadf57 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) |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 |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 [daily build project](https://github.com/Neilpang/acmetest): +For all build statuses, check our [weekly build project](https://github.com/Neilpang/acmetest): https://github.com/Neilpang/acmetest From ded4469efe8a61e94d4878c80420cac414c4e6d2 Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 26 May 2017 14:58:52 +0800 Subject: [PATCH 384/620] fix for openbsd, sed doesn't support `I` option. --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index f255c43f..737d6a7c 100755 --- a/acme.sh +++ b/acme.sh @@ -456,9 +456,9 @@ _h2b() { if [ -z "$_URGLY_PRINTF" ]; then if _exists xargs; then _debug2 "xargs" - echo "$hex" | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/gI' | xargs printf + echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/g' | xargs printf else - for h in $(echo "$hex" | sed 's/\([0-9A-F]\{2\}\)/ \1/gI'); do + for h in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/ \1/g'); do if [ -z "$h" ]; then break fi @@ -466,7 +466,7 @@ _h2b() { done fi else - for c in $(echo "$hex" | sed 's/\([0-9A-F]\)/ \1/gI'); do + for c in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\)/ \1/g'); do if [ -z "$ic" ]; then ic=$c continue From 6185244754718adbe99e564886a443f803a31583 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 27 May 2017 19:28:12 +0800 Subject: [PATCH 385/620] fix doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ddadf57..13188982 100644 --- a/README.md +++ b/README.md @@ -199,7 +199,7 @@ The ownership and permission info of existing files are preserved. You may want Install/copy the issued cert/key to the production Apache or Nginx path. -The cert will be `renewed every **60** days by default` (which is configurable). Once the cert is renewed, the Apache/Nginx service will be restarted automatically by the command: `service apache2 restart` or `service nginx restart`. +The cert will be renewed every **60** days by default (which is configurable). Once the cert is renewed, the Apache/Nginx service will be reloaded automatically by the command: `service apache2 force-reload` or `service nginx force-reload`. # 4. Use Standalone server to issue cert From f8bcfeb2ab7b1c4486309b673b557c4ad2ea5df7 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 29 May 2017 17:07:59 +0800 Subject: [PATCH 386/620] fix xargs issue for freebsd https://github.com/Neilpang/acme.sh/issues/865#issuecomment-304599955 --- acme.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 737d6a7c..60f0fd48 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.0 +VER=2.7.1 PROJECT_NAME="acme.sh" @@ -443,6 +443,11 @@ if [ "$(printf '\x41')" != 'A' ]; then _URGLY_PRINTF=1 fi +_ESCAPE_XARGS="" +if [ "$(printf %s '\\x41' | xargs printf)" == 'A' ]; then + _ESCAPE_XARGS=1 +fi + _h2b() { if _exists xxd; then xxd -r -p @@ -454,7 +459,7 @@ _h2b() { jc="" _debug2 _URGLY_PRINTF "$_URGLY_PRINTF" if [ -z "$_URGLY_PRINTF" ]; then - if _exists xargs; then + if [ "$_ESCAPE_XARGS" ] && _exists xargs; then _debug2 "xargs" echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/g' | xargs printf else From 8a420dd853667db64ca1ac4e6618fd5040c5e89d Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 29 May 2017 17:17:14 +0800 Subject: [PATCH 387/620] fix https://github.com/Neilpang/acme.sh/issues/865#issuecomment-304599955 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 60f0fd48..5f500045 100755 --- a/acme.sh +++ b/acme.sh @@ -444,7 +444,7 @@ if [ "$(printf '\x41')" != 'A' ]; then fi _ESCAPE_XARGS="" -if [ "$(printf %s '\\x41' | xargs printf)" == 'A' ]; then +if [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then _ESCAPE_XARGS=1 fi From df711b0ea2a4ee2737392d68bf7df815f47cc737 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 4 Jun 2017 22:04:43 +0800 Subject: [PATCH 388/620] minor, add debug info --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 5f500045..4261d322 100755 --- a/acme.sh +++ b/acme.sh @@ -2579,7 +2579,7 @@ location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { _err "write nginx conf error, but don't worry, the file is restored." return 1 fi - + _debug3 "Modified config:$(cat $FOUND_REAL_NGINX_CONF)" _info "nginx conf is done, let's check it again." if ! _exec "nginx -t" >/dev/null; then _exec_err From 674790a511803c062c64dcc6999f378f9939fd37 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 5 Jun 2017 22:14:58 +0800 Subject: [PATCH 389/620] add more detect for nginx mode --- acme.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 4261d322..64bcf844 100755 --- a/acme.sh +++ b/acme.sh @@ -2665,7 +2665,8 @@ _isRealNginxConf() { _debug "_seg_n" "$_seg_n" - if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ]; then + if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ] + || [ "$(echo "$_seg_n" | _egrep_o "listen .* ssl[ |;]")" ]; then _debug "ssl on, skip" return 1 fi From 7c67e3d7e231cc80ed6f5b86618ebc9db17da21a Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 5 Jun 2017 22:18:03 +0800 Subject: [PATCH 390/620] fix typo --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 64bcf844..437706d3 100755 --- a/acme.sh +++ b/acme.sh @@ -2665,7 +2665,7 @@ _isRealNginxConf() { _debug "_seg_n" "$_seg_n" - if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ] + if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ] \ || [ "$(echo "$_seg_n" | _egrep_o "listen .* ssl[ |;]")" ]; then _debug "ssl on, skip" return 1 From 241cfc4342177e8ebd3bedcd842f09ebc4783400 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 5 Jun 2017 22:29:21 +0800 Subject: [PATCH 391/620] fix nginx mode issue for multiple entries --- acme.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 437706d3..efe68c18 100755 --- a/acme.sh +++ b/acme.sh @@ -2668,10 +2668,11 @@ _isRealNginxConf() { if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ] \ || [ "$(echo "$_seg_n" | _egrep_o "listen .* ssl[ |;]")" ]; then _debug "ssl on, skip" - return 1 - fi - FOUND_REAL_NGINX_CONF_LN=$_fln - return 0 + else + FOUND_REAL_NGINX_CONF_LN=$_fln + _debug3 "found FOUND_REAL_NGINX_CONF_LN" "$FOUND_REAL_NGINX_CONF_LN" + return 0 + fi fi done fi From 450efea191cc177cfaea01b4c50ce5fdef0fc2a0 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 5 Jun 2017 22:55:16 +0800 Subject: [PATCH 392/620] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index efe68c18..ffbc69b5 100755 --- a/acme.sh +++ b/acme.sh @@ -2672,7 +2672,7 @@ _isRealNginxConf() { FOUND_REAL_NGINX_CONF_LN=$_fln _debug3 "found FOUND_REAL_NGINX_CONF_LN" "$FOUND_REAL_NGINX_CONF_LN" return 0 - fi + fi fi done fi From 8e845d9f2196a43c4423aa9e6419ad87d8072ded Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 6 Jun 2017 10:08:09 +0800 Subject: [PATCH 393/620] make install command respect LE_CONFIG_HOME env --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index ffbc69b5..2e069244 100755 --- a/acme.sh +++ b/acme.sh @@ -4640,6 +4640,11 @@ install() { return 1 fi + if [ -z "$_c_home" ] && [ "$LE_CONFIG_HOME" != "$LE_WORKING_DIR" ]; then + _info "Using config home: $LE_CONFIG_HOME" + _c_home="$LE_CONFIG_HOME" + fi + #convert from le if [ -d "$HOME/.le" ]; then for envfile in "le.env" "le.sh.env"; do From 0b52645bb6afad03cb3c5fcab57e160ecadbf41b Mon Sep 17 00:00:00 2001 From: Rikard Gynnerstedt Date: Thu, 8 Jun 2017 13:32:05 +0200 Subject: [PATCH 394/620] added view variable to infoblox integration script --- dnsapi/dns_infoblox.sh | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 3846e62e..7bb0b5a4 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/bin/bash ## Infoblox API integration by Jason Keller and Elijah Tenai ## @@ -9,7 +9,7 @@ dns_infoblox_add() { ## Nothing to see here, just some housekeeping fulldomain=$1 txtvalue=$2 - baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue" + baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View" _info "Using Infoblox API" _debug fulldomain "$fulldomain" @@ -19,11 +19,15 @@ dns_infoblox_add() { if [ -z "$Infoblox_Creds" ] || [ -z "$Infoblox_Server" ]; then Infoblox_Creds="" Infoblox_Server="" - _err "You didn't specify the credentials or server yet (Infoblox_Creds and Infoblox_Server)." - _err "Please set them via EXPORT ([username:password] and [ip or hostname]) and try again." + _err "You didn't specify the credentials, server or infoblox view yet (Infoblox_Creds, Infoblox_Server and Infoblox_View)." + _err "Please set them via EXPORT ([username:password], [ip or hostname]) and try again." return 1 fi + if [ -z "$Infoblox_View" ]; then + Infoblox_View="default" + fi + ## Save the credentials to the account file _saveaccountconf Infoblox_Creds "$Infoblox_Creds" _saveaccountconf Infoblox_Server "$Infoblox_Server" @@ -39,7 +43,7 @@ dns_infoblox_add() { result=$(_post "" "$baseurlnObject" "" "POST") ## Let's see if we get something intelligible back from the unit - if echo "$result" | egrep 'record:txt/.*:.*/default'; then + if echo "$result" | egrep "record:txt/.*:.*/${Infoblox_View}"; then _info "Successfully created the txt record" return 0 else @@ -68,18 +72,18 @@ dns_infoblox_rm() { export _H2="Authorization: Basic $Infoblox_CredsEncoded" ## Does the record exist? Let's check. - baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&_return_type=xml-pretty" + baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View&_return_type=xml-pretty" result=$(_get "$baseurlnObject") ## Let's see if we get something intelligible back from the grid if echo "$result" | egrep 'record:txt/.*:.*/default'; then ## Extract the object reference - objRef=$(printf "%b" "$result" | _egrep_o 'record:txt/.*:.*/default') + objRef=$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/${Infoblox_View}") objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" ## Delete them! All the stale records! rmResult=$(_post "" "$objRmUrl" "" "DELETE") ## Let's see if that worked - if echo "$rmResult" | egrep 'record:txt/.*:.*/default'; then + if echo "$rmResult" | egrep "record:txt/.*:.*/${Infoblox_View}"; then _info "Successfully deleted $objRef" return 0 else @@ -94,4 +98,4 @@ dns_infoblox_rm() { fi } -#################### Private functions below ################################## +#################### Private functions below ################################## \ No newline at end of file From 0bd4a4f98fcb8c1b8816e2b8a90322e826aa2050 Mon Sep 17 00:00:00 2001 From: Rikard Gynnerstedt Date: Thu, 8 Jun 2017 13:34:29 +0200 Subject: [PATCH 395/620] formated for sh instead of bash --- dnsapi/dns_infoblox.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 7bb0b5a4..a88b4c02 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/env sh ## Infoblox API integration by Jason Keller and Elijah Tenai ## @@ -43,7 +43,7 @@ dns_infoblox_add() { result=$(_post "" "$baseurlnObject" "" "POST") ## Let's see if we get something intelligible back from the unit - if echo "$result" | egrep "record:txt/.*:.*/${Infoblox_View}"; then + if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then _info "Successfully created the txt record" return 0 else @@ -78,12 +78,12 @@ dns_infoblox_rm() { ## Let's see if we get something intelligible back from the grid if echo "$result" | egrep 'record:txt/.*:.*/default'; then ## Extract the object reference - objRef=$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/${Infoblox_View}") + objRef=$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View") objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" ## Delete them! All the stale records! rmResult=$(_post "" "$objRmUrl" "" "DELETE") ## Let's see if that worked - if echo "$rmResult" | egrep "record:txt/.*:.*/${Infoblox_View}"; then + if echo "$rmResult" | egrep "record:txt/.*:.*/$Infoblox_View"; then _info "Successfully deleted $objRef" return 0 else From b6f00ea241b7d42eedbafb9e5b208465b5b7572a Mon Sep 17 00:00:00 2001 From: Rikard Gynnerstedt Date: Thu, 8 Jun 2017 13:35:27 +0200 Subject: [PATCH 396/620] changed path to env --- dnsapi/dns_infoblox.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index a88b4c02..5a00bfd4 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -1,4 +1,4 @@ -#!/bin/env sh +#!/usr/bin/env sh ## Infoblox API integration by Jason Keller and Elijah Tenai ## From eef4acd07d5dcad20e5bbf9335dc556969a7c156 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 14 Jun 2017 23:25:20 +0800 Subject: [PATCH 397/620] fix https://github.com/Neilpang/acme.sh/issues/874 --- dnsapi/dns_dynu.sh | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/dnsapi/dns_dynu.sh b/dnsapi/dns_dynu.sh index f6eabde2..17a1cdb0 100644 --- a/dnsapi/dns_dynu.sh +++ b/dnsapi/dns_dynu.sh @@ -122,18 +122,30 @@ dns_dynu_rm() { # _domain_name=domain.com _get_root() { domain=$1 - if ! _dynu_rest GET "dns/getroot/$domain"; 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" "domain_name"; then - _debug "Domain name not found." - return 1 - fi + if ! _dynu_rest GET "dns/get/$h"; then + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _domain_name=$h + _node=$(printf "%s" "$domain" | cut -d . -f 1-$p) + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 - _domain_name=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 1 | cut -d : -f 2 | cut -d '"' -f 2) - _node=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 3 | cut -d : -f 2 | cut -d '"' -f 2) - return 0 } _get_recordid() { From 3b74ac841ec8b8cd6ffbcc1c0b1c314f4010b9a4 Mon Sep 17 00:00:00 2001 From: Rikard Gynnerstedt Date: Wed, 14 Jun 2017 23:52:48 +0200 Subject: [PATCH 398/620] save Infoblox_View to account config --- dnsapi/dns_infoblox.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 5a00bfd4..78c49767 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -31,6 +31,7 @@ dns_infoblox_add() { ## Save the credentials to the account file _saveaccountconf Infoblox_Creds "$Infoblox_Creds" _saveaccountconf Infoblox_Server "$Infoblox_Server" + _saveaccountconf Infoblox_View "$Infoblox_View" ## Base64 encode the credentials Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) From b73f5a4e94704fa80f1240ab9a61ed81838cfc60 Mon Sep 17 00:00:00 2001 From: Rikard Gynnerstedt Date: Thu, 15 Jun 2017 00:16:26 +0200 Subject: [PATCH 399/620] missed one egrep command --- dnsapi/dns_infoblox.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 78c49767..da274bdb 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -77,7 +77,7 @@ dns_infoblox_rm() { result=$(_get "$baseurlnObject") ## Let's see if we get something intelligible back from the grid - if echo "$result" | egrep 'record:txt/.*:.*/default'; then + if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then ## Extract the object reference objRef=$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View") objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" From 65b22b493cc55f6969d56886c372f92fb1268ff2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 15 Jun 2017 21:26:14 +0800 Subject: [PATCH 400/620] minor, debug info --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index ffbc69b5..8b31f9ac 100755 --- a/acme.sh +++ b/acme.sh @@ -2723,7 +2723,7 @@ _clearup() { _clearupdns() { _debug "_clearupdns" if [ "$dnsadded" != 1 ] || [ -z "$vlist" ]; then - _debug "Dns not added, skip." + _debug "skip dns." return fi From 326c386b2e9675e2719e9e1ee45d0d436640d4e5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 15 Jun 2017 21:44:10 +0800 Subject: [PATCH 401/620] add debug message --- acme.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/acme.sh b/acme.sh index f36ea2ed..d57aacc6 100755 --- a/acme.sh +++ b/acme.sh @@ -151,6 +151,13 @@ _dlg_versions() { echo "apache doesn't exists." fi + echo "nginx:" + if _exists "nginx"; then + nginx -V 2>&1 + else + echo "nginx doesn't exists." + fi + echo "nc:" if _exists "nc"; then nc -h 2>&1 From f3dc5dd12fbe4b369595a90a8a048d23158f3cc4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 16 Jun 2017 21:45:14 +0800 Subject: [PATCH 402/620] fix https://github.com/Neilpang/acme.sh/issues/881#issuecomment-309026385 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d57aacc6..ad700667 100755 --- a/acme.sh +++ b/acme.sh @@ -1733,7 +1733,7 @@ _send_signed_request() { nonce="$_CACHED_NONCE" _debug2 nonce "$nonce" - protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" + protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2" _debug3 protected "$protected" protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" From fcc0aef7f4b9da6a0cccda482b7a94a8cb3e3836 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 16 Jun 2017 22:41:33 +0800 Subject: [PATCH 403/620] start 2.7.2 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index ad700667..84de9824 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.1 +VER=2.7.2 PROJECT_NAME="acme.sh" From 2a188905daa83d645ddba3ec6034231e7e51941a Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 15:49:45 +0800 Subject: [PATCH 404/620] support `--server` --- acme.sh | 104 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 19 deletions(-) diff --git a/acme.sh b/acme.sh index 84de9824..70381336 100755 --- a/acme.sh +++ b/acme.sh @@ -13,7 +13,8 @@ _SCRIPT_="$0" _SUB_FOLDERS="dnsapi deploy" -DEFAULT_CA="https://acme-v01.api.letsencrypt.org" +_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" +DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory" DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" @@ -24,7 +25,7 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048 DEFAULT_OPENSSL_BIN="openssl" -STAGE_CA="https://acme-staging.api.letsencrypt.org" +STAGE_CA="https://acme-staging.api.letsencrypt.org/directory" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" @@ -1714,8 +1715,8 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then - _debug2 "Get nonce." - nonceurl="$API/directory" + _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" + nonceurl="$ACME_DIRECTORY" _headers="$(_get "$nonceurl" "onlyheader")" if [ "$?" != "0" ]; then @@ -2169,6 +2170,53 @@ __initHome() { fi } +#server +_initAPI() { + _api_server="${1:-$ACME_DIRECTORY}" + _debug "_init api for server: $_api_server" + + if [ "$_api_server" = "$DEFAULT_CA" ]; then + #just for performance, hardcode the default entry points + export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" + export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz" + export ACME_NEW_CERT="https://acme-v01.api.letsencrypt.org/acme/new-cert" + export ACME_NEW_REG="https://acme-v01.api.letsencrypt.org/acme/new-reg" + export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert" + fi + + if [ -z "$ACME_KEY_CHANGE" ]; then + response=$(_get "$_api_server") + if [ "$?" != "0" ]; then + _debug2 "response" "$response" + _err "Can not init api." + return 1 + fi + _debug2 "response" "$response" + + ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_KEY_CHANGE + + ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_AUTHZ + + ACME_NEW_CERT=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_CERT + + ACME_NEW_REG=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_REG + + ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_REVOKE_CERT + + fi + + _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" + _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" + _debug "ACME_NEW_CERT" "$ACME_NEW_CERT" + _debug "ACME_NEW_REG" "$ACME_NEW_REG" + _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" +} + #[domain] [keylength] _initpath() { @@ -2189,17 +2237,19 @@ _initpath() { CA_HOME="$DEFAULT_CA_HOME" fi - if [ -z "$API" ]; then + if [ -z "$ACME_DIRECTORY" ]; then if [ -z "$STAGE" ]; then - API="$DEFAULT_CA" + ACME_DIRECTORY="$DEFAULT_CA" else - API="$STAGE_CA" - _info "Using stage api:$API" + ACME_DIRECTORY="$STAGE_CA" + _info "Using stage ACME_DIRECTORY: $ACME_DIRECTORY" fi fi - _API_HOST="$(echo "$API" | cut -d : -f 2 | tr -d '/')" - CA_DIR="$CA_HOME/$_API_HOST" + _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -d '/')" + _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" + + CA_DIR="$CA_HOME/$_ACME_SERVER_HOST" _DEFAULT_CA_CONF="$CA_DIR/ca.conf" @@ -3020,7 +3070,7 @@ _regAccount() { if ! _calcjwk "$ACCOUNT_KEY_PATH"; then return 1 fi - + _initAPI _updateTos="" _reg_res="new-reg" while true; do @@ -3035,7 +3085,7 @@ _regAccount() { if [ -z "$_updateTos" ]; then _info "Registering account" - if ! _send_signed_request "$API/acme/new-reg" "$regjson"; then + if ! _send_signed_request "${ACME_NEW_REG}" "$regjson"; then _err "Register account Error: $response" return 1 fi @@ -3126,7 +3176,7 @@ __get_domain_new_authz() { _authz_i=0 while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do _debug "Try new-authz for the $_authz_i time." - if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then + if ! _send_signed_request "${ACME_NEW_AUTHZ}" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then _err "Can not get domain new authz." return 1 fi @@ -3204,13 +3254,16 @@ issue() { if [ "$_web_roots" = "dns-cx" ]; then _web_roots="dns_cx" fi - _debug "Using api: $API" if [ ! "$IS_RENEW" ]; then _initpath "$_main_domain" "$_key_length" mkdir -p "$DOMAIN_PATH" fi + _debug "Using ACME_DIRECTORY: $ACME_DIRECTORY" + + _initAPI + if [ -f "$DOMAIN_CONF" ]; then Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) _debug Le_NextRenewTime "$Le_NextRenewTime" @@ -3244,7 +3297,7 @@ issue() { _cleardomainconf "Le_LocalAddress" fi - Le_API="$API" + Le_API="$ACME_DIRECTORY" _savedomainconf "Le_API" "$Le_API" if [ "$_alt_domains" = "$NO_VALUE" ]; then @@ -3683,7 +3736,7 @@ issue() { _info "Verify finished, start to sign." der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" - if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then + if ! _send_signed_request "${ACME_NEW_CERT}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 @@ -3736,7 +3789,8 @@ issue() { Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') if ! _contains "$Le_LinkIssuer" ":"; then - Le_LinkIssuer="$API$Le_LinkIssuer" + _info "$(__red "Relative issuer link found.")" + Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" fi _debug Le_LinkIssuer "$Le_LinkIssuer" _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" @@ -3852,7 +3906,11 @@ renew() { . "$DOMAIN_CONF" if [ "$Le_API" ]; then - API="$Le_API" + if [ "$_OLD_CA_HOST" = "$Le_API" ]; then + export Le_API="$DEFAULT_CA" + _savedomainconf Le_API "$Le_API" + fi + export ACME_DIRECTORY="$Le_API" #reload ca configs ACCOUNT_KEY_PATH="" ACCOUNT_JSON_PATH="" @@ -4315,8 +4373,10 @@ revoke() { return 1 fi + _initAPI + data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" - uri="$API/acme/revoke-cert" + uri="${ACME_REVOKE_CERT}" if [ -f "$CERT_KEY_PATH" ]; then _info "Try domain key first." @@ -4875,6 +4935,7 @@ Parameters: --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. + --server SERVER ACME Directory Resource URI. (default: https://acme-v01.api.letsencrypt.org/directory) --accountconf Specifies a customized account config file. --home Specifies the home dir for $PROJECT_NAME . --cert-home Specifies the home dir to save all the certs, only valid for '--install' command. @@ -5150,6 +5211,11 @@ _process() { --staging | --test) STAGE="1" ;; + --server) + ACME_DIRECTORY="$2" + export ACME_DIRECTORY + shift + ;; --debug) if [ -z "$2" ] || _startswith "$2" "-"; then DEBUG="$DEBUG_LEVEL_DEFAULT" From f8c1d97a258f8c8769facee5432a78cfc4dabefb Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 15:59:27 +0800 Subject: [PATCH 405/620] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 70381336..2c2130d5 100755 --- a/acme.sh +++ b/acme.sh @@ -2174,7 +2174,7 @@ __initHome() { _initAPI() { _api_server="${1:-$ACME_DIRECTORY}" _debug "_init api for server: $_api_server" - + if [ "$_api_server" = "$DEFAULT_CA" ]; then #just for performance, hardcode the default entry points export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" From 287623df58d0603056e560a7c046585237dfe249 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 16:20:32 +0800 Subject: [PATCH 406/620] fix for deactivate function --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 2c2130d5..e1e66d85 100755 --- a/acme.sh +++ b/acme.sh @@ -3171,7 +3171,7 @@ _findHook() { __get_domain_new_authz() { _gdnd="$1" _info "Getting new-authz for domain" "$_gdnd" - + _initAPI _Max_new_authz_retry_times=5 _authz_i=0 while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do From cbb74c984fa52d44137cf9f62421e4422312c991 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 16:30:04 +0800 Subject: [PATCH 407/620] minor --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index e1e66d85..27d1cc49 100755 --- a/acme.sh +++ b/acme.sh @@ -4508,6 +4508,7 @@ deactivate() { _d_domain_list="$1" _d_type="$2" _initpath + _initAPI _debug _d_domain_list "$_d_domain_list" if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then _usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]" From ce59fc6c102ec113921c1a20b81a487316e2db79 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 17:15:37 +0800 Subject: [PATCH 408/620] fix renew for stage cert --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index 27d1cc49..d2c8cf24 100755 --- a/acme.sh +++ b/acme.sh @@ -26,6 +26,7 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048 DEFAULT_OPENSSL_BIN="openssl" STAGE_CA="https://acme-staging.api.letsencrypt.org/directory" +_OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" @@ -3910,6 +3911,10 @@ renew() { export Le_API="$DEFAULT_CA" _savedomainconf Le_API "$Le_API" fi + if [ "$_OLD_STAGE_CA_HOST" = "$Le_API" ]; then + export Le_API="$STAGE_CA" + _savedomainconf Le_API "$Le_API" + fi export ACME_DIRECTORY="$Le_API" #reload ca configs ACCOUNT_KEY_PATH="" From 0a301cdd21f37a1b22da6c5709d82c3b526703e8 Mon Sep 17 00:00:00 2001 From: Rikard Gynnerstedt Date: Sat, 17 Jun 2017 11:28:49 +0200 Subject: [PATCH 409/620] added new line at the end of the file --- dnsapi/dns_infoblox.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index da274bdb..06ac87ec 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -99,4 +99,4 @@ dns_infoblox_rm() { fi } -#################### Private functions below ################################## \ No newline at end of file +#################### Private functions below ################################## From 395fbbfd14737e7a70322ff0c1e3fe8d0e2161cf Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 20:49:45 +0800 Subject: [PATCH 410/620] fix cron --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4cb33139..5254bd11 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,7 +50,7 @@ RUN for verb in help \ RUN printf "%b" '#!'"/usr/bin/env sh\n \ if [ \"\$1\" = \"daemon\" ]; then \n \ - crond; tail -f /dev/null;\n \ + crond -f\n \ else \n \ /root/.acme.sh/acme.sh --config-home /acme.sh \"\$@\"\n \ fi" >/entry.sh && chmod +x /entry.sh From b9a972bccd0935b4042db950cb4f86bbd07afec4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Jun 2017 09:52:59 +0800 Subject: [PATCH 411/620] fix openssl 1.1.0 for https://github.com/Neilpang/acme.sh/issues/888 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 84de9824..e79680c0 100755 --- a/acme.sh +++ b/acme.sh @@ -1093,7 +1093,7 @@ _readSubjectFromCSR() { _usage "_readSubjectFromCSR mycsr.csr" return 1 fi - ${ACME_OPENSSL_BIN:-openssl} req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' + ${ACME_OPENSSL_BIN:-openssl} req -noout -in "$_csrfile" -subject | tr ',' "\n" | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d ' \n' } #_csrfile From b963dadc14579609671793b4aa348433a5d345fd Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Jun 2017 10:07:23 +0800 Subject: [PATCH 412/620] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e79680c0..8c067fd2 100755 --- a/acme.sh +++ b/acme.sh @@ -1093,7 +1093,7 @@ _readSubjectFromCSR() { _usage "_readSubjectFromCSR mycsr.csr" return 1 fi - ${ACME_OPENSSL_BIN:-openssl} req -noout -in "$_csrfile" -subject | tr ',' "\n" | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d ' \n' + ${ACME_OPENSSL_BIN:-openssl} req -noout -in "$_csrfile" -subject | tr ',' "\n" | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d ' \n' } #_csrfile From 2c9ed4c565c90833e38fc838a14455c8da8f55f8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Jun 2017 10:18:20 +0800 Subject: [PATCH 413/620] check invalid subject cn in the csr fix https://github.com/Neilpang/acme.sh/issues/805 --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index 8c067fd2..9ff8001f 100755 --- a/acme.sh +++ b/acme.sh @@ -3940,6 +3940,10 @@ signcsr() { return 1 fi _debug _csrsubj "$_csrsubj" + if _contains "$_csrsubj" ' ' || ! _contains "$_csrsubj" '.'; then + _info "It seems that the subject: $_csrsubj is not a valid domain name. Drop it." + _csrsubj="" + fi _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile") if [ "$?" != "0" ]; then From 08b4e1a744000db29a0014de86684701602575c1 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 18 Jun 2017 22:13:33 +0800 Subject: [PATCH 414/620] add ACME_NO_COLOR and `--no-color` not to ouput color text --- acme.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 1ddec824..f20d935f 100755 --- a/acme.sh +++ b/acme.sh @@ -104,21 +104,21 @@ if [ -t 1 ]; then fi __green() { - if [ "$__INTERACTIVE" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then printf '\033[1;31;32m' fi printf -- "%b" "$1" - if [ "$__INTERACTIVE" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then printf '\033[0m' fi } __red() { - if [ "$__INTERACTIVE" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then printf '\033[1;31;40m' fi printf -- "%b" "$1" - if [ "$__INTERACTIVE" ]; then + if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then printf '\033[0m' fi } @@ -4896,6 +4896,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. + --no-color Do not output color text. --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' --csr Specifies the input csr. --pre-hook Command to be run before obtaining any certificates. @@ -5343,6 +5344,9 @@ _process() { --nocron) _nocron="1" ;; + --no-color) + export ACME_NO_COLOR=1 + ;; --ecc) _ecc="isEcc" ;; From 8afec596aabe4795036b7387e092c7cb4cd6995b Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:05:43 +0800 Subject: [PATCH 415/620] fix https://github.com/Neilpang/acme.sh/issues/882#issuecomment-309383956 --- acme.sh | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/acme.sh b/acme.sh index d2c8cf24..c9c58074 100755 --- a/acme.sh +++ b/acme.sh @@ -1716,9 +1716,18 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then - _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" - nonceurl="$ACME_DIRECTORY" - _headers="$(_get "$nonceurl" "onlyheader")" + if [ "$ACME_NEW_NONCE" ]; then + _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE" + nonceurl="$ACME_NEW_NONCE" + if _post "" "$nonceurl" "" "HEAD"; then + _headers="$(cat "$HTTP_HEADER")" + fi + fi + if [ -z "$_headers" ]; then + _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" + nonceurl="$ACME_DIRECTORY" + _headers="$(_get "$nonceurl" "onlyheader")" + fi if [ "$?" != "0" ]; then _err "Can not connect to $nonceurl to get nonce." @@ -2180,12 +2189,12 @@ _initAPI() { #just for performance, hardcode the default entry points export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz" - export ACME_NEW_CERT="https://acme-v01.api.letsencrypt.org/acme/new-cert" - export ACME_NEW_REG="https://acme-v01.api.letsencrypt.org/acme/new-reg" + export ACME_NEW_ORDER="https://acme-v01.api.letsencrypt.org/acme/new-cert" + export ACME_NEW_ACCOUNT="https://acme-v01.api.letsencrypt.org/acme/new-reg" export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert" fi - if [ -z "$ACME_KEY_CHANGE" ]; then + if [ -z "$ACME_NEW_ACCOUNT" ]; then response=$(_get "$_api_server") if [ "$?" != "0" ]; then _debug2 "response" "$response" @@ -2200,21 +2209,30 @@ _initAPI() { ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_NEW_AUTHZ - ACME_NEW_CERT=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) - export ACME_NEW_CERT + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_ORDER" ]; then + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_NEW_ORDER - ACME_NEW_REG=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) - export ACME_NEW_REG + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_ACCOUNT" ]; then + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_NEW_ACCOUNT ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_REVOKE_CERT + ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_NONCE + fi _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" - _debug "ACME_NEW_CERT" "$ACME_NEW_CERT" - _debug "ACME_NEW_REG" "$ACME_NEW_REG" + _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" + _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" } @@ -3086,7 +3104,7 @@ _regAccount() { if [ -z "$_updateTos" ]; then _info "Registering account" - if ! _send_signed_request "${ACME_NEW_REG}" "$regjson"; then + if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then _err "Register account Error: $response" return 1 fi @@ -3737,7 +3755,7 @@ issue() { _info "Verify finished, start to sign." der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" - if ! _send_signed_request "${ACME_NEW_CERT}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then + if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 From 87f3dc4558dbdb0f54a0adf6d9f2df093bbb6985 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:19:30 +0800 Subject: [PATCH 416/620] fix server host --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index c9c58074..18ed71a7 100755 --- a/acme.sh +++ b/acme.sh @@ -2265,7 +2265,7 @@ _initpath() { fi fi - _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -d '/')" + _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)" _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" CA_DIR="$CA_HOME/$_ACME_SERVER_HOST" @@ -5119,6 +5119,7 @@ _process() { _openssl_bin="" _syslog="" _use_wget="" + _server="" while [ ${#} -gt 0 ]; do case "${1}" in @@ -5237,6 +5238,7 @@ _process() { ;; --server) ACME_DIRECTORY="$2" + _server="$ACME_DIRECTORY" export ACME_DIRECTORY shift ;; @@ -5560,6 +5562,9 @@ _process() { if [ "$DEBUG" ]; then version + if [ "$_server" ]; then + _debug "Using server: $_server" + fi fi case "${_CMD}" in From 1d384e3192a4ace6d3ef708d43e65e0015cd2e1d Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:24:31 +0800 Subject: [PATCH 417/620] minor --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index 18ed71a7..428340d2 100755 --- a/acme.sh +++ b/acme.sh @@ -1716,6 +1716,7 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then + _headers="" if [ "$ACME_NEW_NONCE" ]; then _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE" nonceurl="$ACME_NEW_NONCE" From 48d9a8c18051ecd8bcd2922b14b0f83e99804663 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 15:49:45 +0800 Subject: [PATCH 418/620] support `--server` --- acme.sh | 104 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 19 deletions(-) diff --git a/acme.sh b/acme.sh index f20d935f..ebee1e95 100755 --- a/acme.sh +++ b/acme.sh @@ -13,7 +13,8 @@ _SCRIPT_="$0" _SUB_FOLDERS="dnsapi deploy" -DEFAULT_CA="https://acme-v01.api.letsencrypt.org" +_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" +DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory" DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" @@ -24,7 +25,7 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048 DEFAULT_OPENSSL_BIN="openssl" -STAGE_CA="https://acme-staging.api.letsencrypt.org" +STAGE_CA="https://acme-staging.api.letsencrypt.org/directory" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" @@ -1714,8 +1715,8 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then - _debug2 "Get nonce." - nonceurl="$API/directory" + _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" + nonceurl="$ACME_DIRECTORY" _headers="$(_get "$nonceurl" "onlyheader")" if [ "$?" != "0" ]; then @@ -2169,6 +2170,53 @@ __initHome() { fi } +#server +_initAPI() { + _api_server="${1:-$ACME_DIRECTORY}" + _debug "_init api for server: $_api_server" + + if [ "$_api_server" = "$DEFAULT_CA" ]; then + #just for performance, hardcode the default entry points + export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" + export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz" + export ACME_NEW_CERT="https://acme-v01.api.letsencrypt.org/acme/new-cert" + export ACME_NEW_REG="https://acme-v01.api.letsencrypt.org/acme/new-reg" + export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert" + fi + + if [ -z "$ACME_KEY_CHANGE" ]; then + response=$(_get "$_api_server") + if [ "$?" != "0" ]; then + _debug2 "response" "$response" + _err "Can not init api." + return 1 + fi + _debug2 "response" "$response" + + ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_KEY_CHANGE + + ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_AUTHZ + + ACME_NEW_CERT=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_CERT + + ACME_NEW_REG=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_REG + + ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_REVOKE_CERT + + fi + + _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" + _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" + _debug "ACME_NEW_CERT" "$ACME_NEW_CERT" + _debug "ACME_NEW_REG" "$ACME_NEW_REG" + _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" +} + #[domain] [keylength] _initpath() { @@ -2189,17 +2237,19 @@ _initpath() { CA_HOME="$DEFAULT_CA_HOME" fi - if [ -z "$API" ]; then + if [ -z "$ACME_DIRECTORY" ]; then if [ -z "$STAGE" ]; then - API="$DEFAULT_CA" + ACME_DIRECTORY="$DEFAULT_CA" else - API="$STAGE_CA" - _info "Using stage api:$API" + ACME_DIRECTORY="$STAGE_CA" + _info "Using stage ACME_DIRECTORY: $ACME_DIRECTORY" fi fi - _API_HOST="$(echo "$API" | cut -d : -f 2 | tr -d '/')" - CA_DIR="$CA_HOME/$_API_HOST" + _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -d '/')" + _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" + + CA_DIR="$CA_HOME/$_ACME_SERVER_HOST" _DEFAULT_CA_CONF="$CA_DIR/ca.conf" @@ -3020,7 +3070,7 @@ _regAccount() { if ! _calcjwk "$ACCOUNT_KEY_PATH"; then return 1 fi - + _initAPI _updateTos="" _reg_res="new-reg" while true; do @@ -3035,7 +3085,7 @@ _regAccount() { if [ -z "$_updateTos" ]; then _info "Registering account" - if ! _send_signed_request "$API/acme/new-reg" "$regjson"; then + if ! _send_signed_request "${ACME_NEW_REG}" "$regjson"; then _err "Register account Error: $response" return 1 fi @@ -3126,7 +3176,7 @@ __get_domain_new_authz() { _authz_i=0 while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do _debug "Try new-authz for the $_authz_i time." - if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then + if ! _send_signed_request "${ACME_NEW_AUTHZ}" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then _err "Can not get domain new authz." return 1 fi @@ -3204,13 +3254,16 @@ issue() { if [ "$_web_roots" = "dns-cx" ]; then _web_roots="dns_cx" fi - _debug "Using api: $API" if [ ! "$IS_RENEW" ]; then _initpath "$_main_domain" "$_key_length" mkdir -p "$DOMAIN_PATH" fi + _debug "Using ACME_DIRECTORY: $ACME_DIRECTORY" + + _initAPI + if [ -f "$DOMAIN_CONF" ]; then Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) _debug Le_NextRenewTime "$Le_NextRenewTime" @@ -3244,7 +3297,7 @@ issue() { _cleardomainconf "Le_LocalAddress" fi - Le_API="$API" + Le_API="$ACME_DIRECTORY" _savedomainconf "Le_API" "$Le_API" if [ "$_alt_domains" = "$NO_VALUE" ]; then @@ -3683,7 +3736,7 @@ issue() { _info "Verify finished, start to sign." der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" - if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then + if ! _send_signed_request "${ACME_NEW_CERT}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 @@ -3736,7 +3789,8 @@ issue() { Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') if ! _contains "$Le_LinkIssuer" ":"; then - Le_LinkIssuer="$API$Le_LinkIssuer" + _info "$(__red "Relative issuer link found.")" + Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" fi _debug Le_LinkIssuer "$Le_LinkIssuer" _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" @@ -3852,7 +3906,11 @@ renew() { . "$DOMAIN_CONF" if [ "$Le_API" ]; then - API="$Le_API" + if [ "$_OLD_CA_HOST" = "$Le_API" ]; then + export Le_API="$DEFAULT_CA" + _savedomainconf Le_API "$Le_API" + fi + export ACME_DIRECTORY="$Le_API" #reload ca configs ACCOUNT_KEY_PATH="" ACCOUNT_JSON_PATH="" @@ -4319,8 +4377,10 @@ revoke() { return 1 fi + _initAPI + data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" - uri="$API/acme/revoke-cert" + uri="${ACME_REVOKE_CERT}" if [ -f "$CERT_KEY_PATH" ]; then _info "Try domain key first." @@ -4879,6 +4939,7 @@ Parameters: --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. + --server SERVER ACME Directory Resource URI. (default: https://acme-v01.api.letsencrypt.org/directory) --accountconf Specifies a customized account config file. --home Specifies the home dir for $PROJECT_NAME . --cert-home Specifies the home dir to save all the certs, only valid for '--install' command. @@ -5155,6 +5216,11 @@ _process() { --staging | --test) STAGE="1" ;; + --server) + ACME_DIRECTORY="$2" + export ACME_DIRECTORY + shift + ;; --debug) if [ -z "$2" ] || _startswith "$2" "-"; then DEBUG="$DEBUG_LEVEL_DEFAULT" From 4cee14f3c5503699ffb9c19cc5eb81d9b11265d4 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 15:59:27 +0800 Subject: [PATCH 419/620] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index ebee1e95..676a7201 100755 --- a/acme.sh +++ b/acme.sh @@ -2174,7 +2174,7 @@ __initHome() { _initAPI() { _api_server="${1:-$ACME_DIRECTORY}" _debug "_init api for server: $_api_server" - + if [ "$_api_server" = "$DEFAULT_CA" ]; then #just for performance, hardcode the default entry points export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" From 40ef86f475dcefcc46d3997869079aa0fb3d000e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 16:20:32 +0800 Subject: [PATCH 420/620] fix for deactivate function --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 676a7201..b1ddb500 100755 --- a/acme.sh +++ b/acme.sh @@ -3171,7 +3171,7 @@ _findHook() { __get_domain_new_authz() { _gdnd="$1" _info "Getting new-authz for domain" "$_gdnd" - + _initAPI _Max_new_authz_retry_times=5 _authz_i=0 while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do From a3bdaa85f2c944c828ee74e94669bef4d2f80649 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 16:30:04 +0800 Subject: [PATCH 421/620] minor --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index b1ddb500..43929203 100755 --- a/acme.sh +++ b/acme.sh @@ -4512,6 +4512,7 @@ deactivate() { _d_domain_list="$1" _d_type="$2" _initpath + _initAPI _debug _d_domain_list "$_d_domain_list" if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then _usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]" From 4a2ac7bd2ec2f95bd4974e751dbcac49e8c4e402 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 17:15:37 +0800 Subject: [PATCH 422/620] fix renew for stage cert --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index 43929203..2ee7740c 100755 --- a/acme.sh +++ b/acme.sh @@ -26,6 +26,7 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048 DEFAULT_OPENSSL_BIN="openssl" STAGE_CA="https://acme-staging.api.letsencrypt.org/directory" +_OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" @@ -3910,6 +3911,10 @@ renew() { export Le_API="$DEFAULT_CA" _savedomainconf Le_API "$Le_API" fi + if [ "$_OLD_STAGE_CA_HOST" = "$Le_API" ]; then + export Le_API="$STAGE_CA" + _savedomainconf Le_API "$Le_API" + fi export ACME_DIRECTORY="$Le_API" #reload ca configs ACCOUNT_KEY_PATH="" From cae50e16a71bdf921b9a1bd4708625cf8471278f Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:05:43 +0800 Subject: [PATCH 423/620] fix https://github.com/Neilpang/acme.sh/issues/882#issuecomment-309383956 --- acme.sh | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/acme.sh b/acme.sh index 2ee7740c..81668480 100755 --- a/acme.sh +++ b/acme.sh @@ -1716,9 +1716,18 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then - _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" - nonceurl="$ACME_DIRECTORY" - _headers="$(_get "$nonceurl" "onlyheader")" + if [ "$ACME_NEW_NONCE" ]; then + _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE" + nonceurl="$ACME_NEW_NONCE" + if _post "" "$nonceurl" "" "HEAD"; then + _headers="$(cat "$HTTP_HEADER")" + fi + fi + if [ -z "$_headers" ]; then + _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" + nonceurl="$ACME_DIRECTORY" + _headers="$(_get "$nonceurl" "onlyheader")" + fi if [ "$?" != "0" ]; then _err "Can not connect to $nonceurl to get nonce." @@ -2180,12 +2189,12 @@ _initAPI() { #just for performance, hardcode the default entry points export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz" - export ACME_NEW_CERT="https://acme-v01.api.letsencrypt.org/acme/new-cert" - export ACME_NEW_REG="https://acme-v01.api.letsencrypt.org/acme/new-reg" + export ACME_NEW_ORDER="https://acme-v01.api.letsencrypt.org/acme/new-cert" + export ACME_NEW_ACCOUNT="https://acme-v01.api.letsencrypt.org/acme/new-reg" export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert" fi - if [ -z "$ACME_KEY_CHANGE" ]; then + if [ -z "$ACME_NEW_ACCOUNT" ]; then response=$(_get "$_api_server") if [ "$?" != "0" ]; then _debug2 "response" "$response" @@ -2200,21 +2209,30 @@ _initAPI() { ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_NEW_AUTHZ - ACME_NEW_CERT=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) - export ACME_NEW_CERT + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_ORDER" ]; then + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_NEW_ORDER - ACME_NEW_REG=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) - export ACME_NEW_REG + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_ACCOUNT" ]; then + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_NEW_ACCOUNT ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_REVOKE_CERT + ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_NONCE + fi _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" - _debug "ACME_NEW_CERT" "$ACME_NEW_CERT" - _debug "ACME_NEW_REG" "$ACME_NEW_REG" + _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" + _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" } @@ -3086,7 +3104,7 @@ _regAccount() { if [ -z "$_updateTos" ]; then _info "Registering account" - if ! _send_signed_request "${ACME_NEW_REG}" "$regjson"; then + if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then _err "Register account Error: $response" return 1 fi @@ -3737,7 +3755,7 @@ issue() { _info "Verify finished, start to sign." der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" - if ! _send_signed_request "${ACME_NEW_CERT}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then + if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 From 98394f99b5649be9df419fd3bed5bfef4658971c Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:19:30 +0800 Subject: [PATCH 424/620] fix server host --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 81668480..a9a9c040 100755 --- a/acme.sh +++ b/acme.sh @@ -2265,7 +2265,7 @@ _initpath() { fi fi - _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -d '/')" + _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)" _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" CA_DIR="$CA_HOME/$_ACME_SERVER_HOST" @@ -5124,6 +5124,7 @@ _process() { _openssl_bin="" _syslog="" _use_wget="" + _server="" while [ ${#} -gt 0 ]; do case "${1}" in @@ -5242,6 +5243,7 @@ _process() { ;; --server) ACME_DIRECTORY="$2" + _server="$ACME_DIRECTORY" export ACME_DIRECTORY shift ;; @@ -5568,6 +5570,9 @@ _process() { if [ "$DEBUG" ]; then version + if [ "$_server" ]; then + _debug "Using server: $_server" + fi fi case "${_CMD}" in From 8f01919f62513ad4daa08db2d292de1040381351 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:24:31 +0800 Subject: [PATCH 425/620] minor --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index a9a9c040..dea5b4a7 100755 --- a/acme.sh +++ b/acme.sh @@ -1716,6 +1716,7 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then + _headers="" if [ "$ACME_NEW_NONCE" ]; then _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE" nonceurl="$ACME_NEW_NONCE" From 88ada806863aaaf3b0037573715d3bd589b3cafe Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 20 Jun 2017 21:51:18 +0800 Subject: [PATCH 426/620] step to 2.7.3 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index dea5b4a7..09cc9fd4 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.2 +VER=2.7.3 PROJECT_NAME="acme.sh" From 841b762796d4909d0bc40cfa7e4a9147aa17e28a Mon Sep 17 00:00:00 2001 From: neil Date: Fri, 23 Jun 2017 18:11:11 +0800 Subject: [PATCH 427/620] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 09cc9fd4..70033523 100755 --- a/acme.sh +++ b/acme.sh @@ -453,7 +453,7 @@ if [ "$(printf '\x41')" != 'A' ]; then fi _ESCAPE_XARGS="" -if [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then +if _exists xargs && [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then _ESCAPE_XARGS=1 fi From eb0ef6bd3dd56af440628b9b0f0edeb3753cf863 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 27 Jun 2017 19:56:43 +0800 Subject: [PATCH 428/620] fix https://github.com/Neilpang/acme.sh/issues/614#issuecomment-311160843 --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 70033523..fa969b0f 100755 --- a/acme.sh +++ b/acme.sh @@ -1138,7 +1138,12 @@ _readKeyLengthFromCSR() { echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' else _debug "RSA CSR" - echo "$_outcsr" | tr "\t" " " | (_egrep_o "^ *Public.Key:.*" || _egrep_o "RSA Public.Key:.*") | cut -d '(' -f 2 | cut -d ' ' -f 1 + _rkl="$(echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1)" + if [ "$_rkl" ]; then + echo "$_rkl" + else + echo "$_outcsr" | tr "\t" " " | _egrep_o "RSA Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 + fi fi } From fa98d72f3a87cf438ba16cccccf61fc268c517df Mon Sep 17 00:00:00 2001 From: RaidenII Date: Tue, 27 Jun 2017 09:21:39 -0400 Subject: [PATCH 429/620] Added preliminary support for DuckDNS TXT record API, a free Dynamic DNS provider --- dnsapi/dns_duckdns.sh | 93 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100755 dnsapi/dns_duckdns.sh diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh new file mode 100755 index 00000000..dc0d49ca --- /dev/null +++ b/dnsapi/dns_duckdns.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env sh + +#Created by RaidenII, to use DuckDNS's API to add/remove text records +#06/27/2017 + +# Currently only support single domain access + +# DuckDNS uses StartSSL as their cert provider +# Seems not supported natively on Linux +# So I fall back to HTTP for API +DuckDNS_API="http://www.duckdns.org/update" + +######## Public functions ##################### + +#Usage: dns_duckdns_add _acme-challenge.domain.duckdns.org "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_duckdns_add() { + fulldomain=$1 + txtvalue=$2 + + # We'll extract the domain/username from full domain + IFS='.' read -r -a fqdn <<< "$fulldomain" + DuckDNS_domain="${fqdn[-3]}" + + if [ -z "$DuckDNS_domain" ]; then + _err "Error extracting the domain." + return 1 + fi + + if [ -z "$DuckDNS_token" ]; then + DuckDNS_token="" + _err "The token for your DuckDNS account is necessary." + _err "You can look it up in your DuckDNS account." + return 1 + fi + + # Now save the credentials. + _saveaccountconf DuckDNS_domain "$DuckDNS_domain" + _saveaccountconf DuckDNS_token "$DuckDNS_token" + + # Unfortunately, DuckDNS does not seems to support lookup domain through API + # So I assume your credentials (which are your domain and token) are correct + # If something goes wrong, we will get a KO response from DuckDNS + + # Now add the TXT record to DuckDNS + _info "Trying to add TXT record" + if _duckdns_rest GET "domains=$DuckDNS_domain&token=$DuckDNS_token&txt=$txtvalue" && [ $response == "OK" ]; then + _info "TXT record has been successfully added to your DuckDNS domain." + _info "Note that all subdomains under this domain uses the same TXT record." + return 0 + else + _err "Errors happened during adding the TXT record." + return 1 + fi +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_duckdns_rm() { + fulldomain=$1 + txtvalue=$2 + + # Now remove the TXT record from DuckDNS + _info "Trying to from TXT record" + if _duckdns_rest GET "domains=$DuckDNS_domain&token=$DuckDNS_token&txt=''&clear=true" && [ $response == "OK" ]; then + _info "TXT record has been successfully removed from your DuckDNS domain." + return 0 + else + _err "Errors happened during removing the TXT record." + return 1 + fi +} + +#################### Private functions below ################################## + +#Usage: method URI data +_duckdns_rest() { + method=$1 + param="$2" + _debug param "$param" + url="$DuckDNS_API?$param" + _debug url "$url" + + # DuckDNS uses GET to update domain info + if [ $method == "GET" ]; then + response="$(_get "$url")" + else + _err "Unsupported method" + return 1 + fi + + _debug response "$response" + return 0 +} From e7dff4756ffef5f14b40363cc2a888977b9d9efd Mon Sep 17 00:00:00 2001 From: RaidenII Date: Tue, 27 Jun 2017 15:28:10 -0400 Subject: [PATCH 430/620] Using HTTPS for DuckDNS API and added instruction. --- dnsapi/dns_duckdns.sh | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index dc0d49ca..847b3fc5 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -4,11 +4,10 @@ #06/27/2017 # Currently only support single domain access +# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure must be used with acme.sh -# DuckDNS uses StartSSL as their cert provider -# Seems not supported natively on Linux -# So I fall back to HTTP for API -DuckDNS_API="http://www.duckdns.org/update" +DuckDNS_API="https://www.duckdns.org/update" +API_Params="domains=$DuckDNS_domain&token=$DuckDNS_token" ######## Public functions ##################### @@ -43,7 +42,7 @@ dns_duckdns_add() { # Now add the TXT record to DuckDNS _info "Trying to add TXT record" - if _duckdns_rest GET "domains=$DuckDNS_domain&token=$DuckDNS_token&txt=$txtvalue" && [ $response == "OK" ]; then + if _duckdns_rest GET "$API_Params&txt=$txtvalue" && [ $response == "OK" ]; then _info "TXT record has been successfully added to your DuckDNS domain." _info "Note that all subdomains under this domain uses the same TXT record." return 0 @@ -60,8 +59,8 @@ dns_duckdns_rm() { txtvalue=$2 # Now remove the TXT record from DuckDNS - _info "Trying to from TXT record" - if _duckdns_rest GET "domains=$DuckDNS_domain&token=$DuckDNS_token&txt=''&clear=true" && [ $response == "OK" ]; then + _info "Trying to remove TXT record" + if _duckdns_rest GET "$API_Params&txt=''&clear=true" && [ $response == "OK" ]; then _info "TXT record has been successfully removed from your DuckDNS domain." return 0 else @@ -72,7 +71,7 @@ dns_duckdns_rm() { #################### Private functions below ################################## -#Usage: method URI data +#Usage: method URI _duckdns_rest() { method=$1 param="$2" From 9dd62ae0f8de8e125edb8396a1b25aba3d712bd3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 28 Jun 2017 19:21:03 +0800 Subject: [PATCH 431/620] fix https://github.com/Neilpang/acme.sh/issues/900 --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5254bd11..8f363852 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,9 +50,10 @@ RUN for verb in help \ RUN printf "%b" '#!'"/usr/bin/env sh\n \ if [ \"\$1\" = \"daemon\" ]; then \n \ - crond -f\n \ + trap \"echo stop && killall crond && exit 0\" SIGTERM SIGINT \n \ + crond && while true; do sleep 1; done;\n \ else \n \ - /root/.acme.sh/acme.sh --config-home /acme.sh \"\$@\"\n \ + exec -- \"\$@\"\n \ fi" >/entry.sh && chmod +x /entry.sh VOLUME /acme.sh From 7d2b6cfeaf888a34526fa291e5d9b5ad350ff6ff Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 28 Jun 2017 19:46:51 +0800 Subject: [PATCH 432/620] fix https://github.com/Neilpang/acme.sh/issues/905 --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 13188982..5b6b03ae 100644 --- a/README.md +++ b/README.md @@ -296,6 +296,9 @@ acme.sh --renew -d example.com Ok, it's finished. +**Take care, this is dns manual mode, it can not be renewed automatically. you will have to add a new txt record to your domain by your hand when you renew your cert.** + +**Please use dns api mode instead.** # 9. Automatic DNS API integration From e64ad5176ef6e4865c0d8fd7da83e318e07ef853 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Wed, 28 Jun 2017 16:15:57 -0400 Subject: [PATCH 433/620] Added Name.com API support. Minor change to DuckDNS API support. --- dnsapi/dns_duckdns.sh | 2 +- dnsapi/dns_namecom.sh | 188 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+), 1 deletion(-) create mode 100755 dnsapi/dns_namecom.sh diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index 847b3fc5..f86d516e 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -60,7 +60,7 @@ dns_duckdns_rm() { # Now remove the TXT record from DuckDNS _info "Trying to remove TXT record" - if _duckdns_rest GET "$API_Params&txt=''&clear=true" && [ $response == "OK" ]; then + if _duckdns_rest GET "$API_Params&txt=&clear=true" && [ $response == "OK" ]; then _info "TXT record has been successfully removed from your DuckDNS domain." return 0 else diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh new file mode 100755 index 00000000..7a84685f --- /dev/null +++ b/dnsapi/dns_namecom.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env sh + +#Author: RaidneII +#Created 06/28/2017 +#Utilize name.com API to finish dns-01 verifications. +######## Public functions ##################### + +namecom_api="https://api.name.com/api/" + +#Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_namecom_add() { + fulldomain=$1 + txtvalue=$2 + + # First we need name.com credentials. + if [ -z "$namecom_username" ]; then + namecom_username="" + _err "Username for name.com is missing." + _err "Please specify that in your environment variable." + return 1 + fi + + if [ -z "$namecom_token" ]; then + namecom_token="" + _err "API token for name.com is missing." + _err "Please specify that in your environment variable." + return 1 + fi + + # Save them in configuration. + _saveaccountconf namecom_username "$namecom_username" + _saveaccountconf namecom_token "$namecom_token" + + # Login in using API + _namecom_login + + # Find domain in domain list. + if ! _namecom_get_root "$fulldomain"; then + _err "Unable to find domain specified." + _namecom_logout + return 1 + fi + + # Add TXT record. + _namecom_addtxt_json="{\"hostname\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":\"300\",\"priority\":\"10\"}" + if _namecom_rest POST "dns/create/$_domain" "$_namecom_addtxt_json"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") + _debug retcode "$retcode" + if [ ! -z "$retcode" ]; then + _info "Successfully added TXT record, ready for validation." + _namecom_logout + return 0 + else + _err "Unable to add the DNS record." + _namecom_logout + return 1 + fi + fi +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_namecom_rm() { + fulldomain=$1 + txtvalue=$2 + + _namecom_login + + # Find domain in domain list. + if ! _namecom_get_root "$fulldomain"; then + _err "Unable to find domain specified." + _namecom_logout + return 1 + fi + + # Get the record id. + if _namecom_rest GET "dns/list/$_domain"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") + _debug retcode "$retcode" + if [ ! -z "$retcode" ]; then + _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d : -f 2 | cut -d \" -f 2) + _debug record_id "$_record_id" + _info "Successfully retrieved the record id for ACME challenge." + else + _err "Unable to retrieve the record id." + _namecom_logout + return 1 + fi + fi + + # Remove the DNS record using record id. + _namecom_rmtxt_json="{\"record_id\":\"$_record_id\"}" + if _namecom_rest POST "dns/delete/$_domain" "$_namecom_rmtxt_json"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") + _debug retcode "$retcode" + if [ ! -z "$retcode" ]; then + _info "Successfully removed the TXT record." + _namecom_logout + return 0 + else + _err "Unable to remove the DNS record." + _namecom_logout + return 1 + fi + fi +} + +#################### Private functions below ################################## +_namecom_rest() { + method=$1 + param=$2 + data=$3 + + export _H1="Content-Type: application/json" + export _H2="Api-Session-Token: $sessionkey" + if [ "$method" != "GET" ]; then + response="$(_post "$data" "$namecom_api/$param" "" "$method")" + else + response="$(_get "$namecom_api/$param")" + fi + + if [ "$?" != "0" ]; then + _err "error $param" + return 1 + fi + + _debug response "$response" + return 0 +} + +_namecom_login() { + namecom_login_json="{\"username\":\"$namecom_username\",\"api_token\":\"$namecom_token\"}" + + if _namecom_rest POST "login" "$namecom_login_json"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") + _debug retcode "$retcode" + if [ ! -z "$retcode" ]; then + _info "Successfully logged in. Fetching session token..." + sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4) + if [ ! -z "$sessionkey" ]; then + _debug sessionkey "$sessionkey" + _info "Session key obtained." + else + _err "Unable to get session key." + return 1 + fi + else + _err "Logging in failed." + return 1 + fi + fi +} + +_namecom_logout() { + if _namecom_rest GET "logout"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") + if [ ! -z "$retcode" ]; then + _info "Successfully logged out." + else + _err "Error logging out." + return 1 + fi + fi +} + +_namecom_get_root() { + domain=$1 + i=2 + p=1 + + if _namecom_rest GET "domain/list"; then + while true; do + host=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$host" ]; then + return 1 + fi + + if _contains "$response" "$host"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$host" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + fi + return 1 +} From 168d712decb687c4ac665b02df716a7de9c99b6e Mon Sep 17 00:00:00 2001 From: RaidenII Date: Thu, 29 Jun 2017 09:43:11 -0400 Subject: [PATCH 434/620] Fixed URL of Name.com API and removed useless debug for retcode. --- dnsapi/dns_namecom.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 7a84685f..158a11b0 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -5,7 +5,7 @@ #Utilize name.com API to finish dns-01 verifications. ######## Public functions ##################### -namecom_api="https://api.name.com/api/" +namecom_api="https://api.name.com/api" #Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_namecom_add() { @@ -45,7 +45,6 @@ dns_namecom_add() { _namecom_addtxt_json="{\"hostname\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":\"300\",\"priority\":\"10\"}" if _namecom_rest POST "dns/create/$_domain" "$_namecom_addtxt_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - _debug retcode "$retcode" if [ ! -z "$retcode" ]; then _info "Successfully added TXT record, ready for validation." _namecom_logout @@ -76,7 +75,6 @@ dns_namecom_rm() { # Get the record id. if _namecom_rest GET "dns/list/$_domain"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - _debug retcode "$retcode" if [ ! -z "$retcode" ]; then _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d : -f 2 | cut -d \" -f 2) _debug record_id "$_record_id" @@ -92,7 +90,6 @@ dns_namecom_rm() { _namecom_rmtxt_json="{\"record_id\":\"$_record_id\"}" if _namecom_rest POST "dns/delete/$_domain" "$_namecom_rmtxt_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - _debug retcode "$retcode" if [ ! -z "$retcode" ]; then _info "Successfully removed the TXT record." _namecom_logout @@ -133,7 +130,6 @@ _namecom_login() { if _namecom_rest POST "login" "$namecom_login_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - _debug retcode "$retcode" if [ ! -z "$retcode" ]; then _info "Successfully logged in. Fetching session token..." sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4) From eeda3062e1c2a79d65e01db192582586e11fb517 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Thu, 29 Jun 2017 15:40:29 -0400 Subject: [PATCH 435/620] Fix against POSIX standard. --- dnsapi/dns_duckdns.sh | 9 ++-- dnsapi/dns_namecom.sh | 104 +++++++++++++++++++++--------------------- 2 files changed, 56 insertions(+), 57 deletions(-) diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index f86d516e..a34c8d36 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -17,8 +17,7 @@ dns_duckdns_add() { txtvalue=$2 # We'll extract the domain/username from full domain - IFS='.' read -r -a fqdn <<< "$fulldomain" - DuckDNS_domain="${fqdn[-3]}" + DuckDNS_domain=$(printf "%s\n" "$fulldomain" | rev | cut -d \. -f 3 | rev) if [ -z "$DuckDNS_domain" ]; then _err "Error extracting the domain." @@ -42,7 +41,7 @@ dns_duckdns_add() { # Now add the TXT record to DuckDNS _info "Trying to add TXT record" - if _duckdns_rest GET "$API_Params&txt=$txtvalue" && [ $response == "OK" ]; then + if _duckdns_rest GET "$API_Params&txt=$txtvalue" && [ "$response" -eq "OK" ]; then _info "TXT record has been successfully added to your DuckDNS domain." _info "Note that all subdomains under this domain uses the same TXT record." return 0 @@ -60,7 +59,7 @@ dns_duckdns_rm() { # Now remove the TXT record from DuckDNS _info "Trying to remove TXT record" - if _duckdns_rest GET "$API_Params&txt=&clear=true" && [ $response == "OK" ]; then + if _duckdns_rest GET "$API_Params&txt=&clear=true" && [ "$response" -eq "OK" ]; then _info "TXT record has been successfully removed from your DuckDNS domain." return 0 else @@ -80,7 +79,7 @@ _duckdns_rest() { _debug url "$url" # DuckDNS uses GET to update domain info - if [ $method == "GET" ]; then + if [ "$method" -eq "GET" ]; then response="$(_get "$url")" else _err "Unsupported method" diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 158a11b0..9a6e81f9 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -45,15 +45,15 @@ dns_namecom_add() { _namecom_addtxt_json="{\"hostname\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":\"300\",\"priority\":\"10\"}" if _namecom_rest POST "dns/create/$_domain" "$_namecom_addtxt_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then - _info "Successfully added TXT record, ready for validation." - _namecom_logout - return 0 - else - _err "Unable to add the DNS record." - _namecom_logout - return 1 - fi + if [ ! -z "$retcode" ]; then + _info "Successfully added TXT record, ready for validation." + _namecom_logout + return 0 + else + _err "Unable to add the DNS record." + _namecom_logout + return 1 + fi fi } @@ -75,30 +75,30 @@ dns_namecom_rm() { # Get the record id. if _namecom_rest GET "dns/list/$_domain"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then - _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d : -f 2 | cut -d \" -f 2) - _debug record_id "$_record_id" - _info "Successfully retrieved the record id for ACME challenge." - else - _err "Unable to retrieve the record id." - _namecom_logout - return 1 - fi + if [ ! -z "$retcode" ]; then + _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d : -f 2 | cut -d \" -f 2) + _debug record_id "$_record_id" + _info "Successfully retrieved the record id for ACME challenge." + else + _err "Unable to retrieve the record id." + _namecom_logout + return 1 + fi fi # Remove the DNS record using record id. _namecom_rmtxt_json="{\"record_id\":\"$_record_id\"}" if _namecom_rest POST "dns/delete/$_domain" "$_namecom_rmtxt_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then - _info "Successfully removed the TXT record." - _namecom_logout - return 0 - else - _err "Unable to remove the DNS record." - _namecom_logout - return 1 - fi + if [ ! -z "$retcode" ]; then + _info "Successfully removed the TXT record." + _namecom_logout + return 0 + else + _err "Unable to remove the DNS record." + _namecom_logout + return 1 + fi fi } @@ -130,32 +130,32 @@ _namecom_login() { if _namecom_rest POST "login" "$namecom_login_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then - _info "Successfully logged in. Fetching session token..." - sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4) - if [ ! -z "$sessionkey" ]; then - _debug sessionkey "$sessionkey" - _info "Session key obtained." - else - _err "Unable to get session key." - return 1 - fi + if [ ! -z "$retcode" ]; then + _info "Successfully logged in. Fetching session token..." + sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4) + if [ ! -z "$sessionkey" ]; then + _debug sessionkey "$sessionkey" + _info "Session key obtained." else - _err "Logging in failed." + _err "Unable to get session key." return 1 fi - fi + else + _err "Logging in failed." + return 1 + fi + fi } _namecom_logout() { if _namecom_rest GET "logout"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then - _info "Successfully logged out." - else - _err "Error logging out." - return 1 - fi + if [ ! -z "$retcode" ]; then + _info "Successfully logged out." + else + _err "Error logging out." + return 1 + fi fi } @@ -171,13 +171,13 @@ _namecom_get_root() { return 1 fi - if _contains "$response" "$host"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - _domain="$host" - return 0 - fi - p=$i - i=$(_math "$i" + 1) + if _contains "$response" "$host"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$host" + return 0 + fi + p=$i + i=$(_math "$i" + 1) done fi return 1 From d0f5aece5f5c1708668faed8e2a7fe5671eceea8 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Thu, 29 Jun 2017 15:43:58 -0400 Subject: [PATCH 436/620] Fix SC2170. --- dnsapi/dns_duckdns.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index a34c8d36..b1937cb8 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -41,7 +41,7 @@ dns_duckdns_add() { # Now add the TXT record to DuckDNS _info "Trying to add TXT record" - if _duckdns_rest GET "$API_Params&txt=$txtvalue" && [ "$response" -eq "OK" ]; then + if _duckdns_rest GET "$API_Params&txt=$txtvalue" && [ "$response" = "OK" ]; then _info "TXT record has been successfully added to your DuckDNS domain." _info "Note that all subdomains under this domain uses the same TXT record." return 0 @@ -59,7 +59,7 @@ dns_duckdns_rm() { # Now remove the TXT record from DuckDNS _info "Trying to remove TXT record" - if _duckdns_rest GET "$API_Params&txt=&clear=true" && [ "$response" -eq "OK" ]; then + if _duckdns_rest GET "$API_Params&txt=&clear=true" && [ "$response" = "OK" ]; then _info "TXT record has been successfully removed from your DuckDNS domain." return 0 else @@ -79,7 +79,7 @@ _duckdns_rest() { _debug url "$url" # DuckDNS uses GET to update domain info - if [ "$method" -eq "GET" ]; then + if [ "$method" = "GET" ]; then response="$(_get "$url")" else _err "Unsupported method" From 17fbfd14db2b71af580afb59cc515f09299ca37e Mon Sep 17 00:00:00 2001 From: RaidenII Date: Fri, 30 Jun 2017 08:32:39 -0400 Subject: [PATCH 437/620] Minor fixes. --- dnsapi/dns_duckdns.sh | 2 +- dnsapi/dns_namecom.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index b1937cb8..cacf5a8c 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -17,7 +17,7 @@ dns_duckdns_add() { txtvalue=$2 # We'll extract the domain/username from full domain - DuckDNS_domain=$(printf "%s\n" "$fulldomain" | rev | cut -d \. -f 3 | rev) + DuckDNS_domain=$(printf "%s\n" "$fulldomain" | rev | cut -d . -f 3 | rev) if [ -z "$DuckDNS_domain" ]; then _err "Error extracting the domain." diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 9a6e81f9..2c5a5df4 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -76,7 +76,7 @@ dns_namecom_rm() { if _namecom_rest GET "dns/list/$_domain"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") if [ ! -z "$retcode" ]; then - _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d : -f 2 | cut -d \" -f 2) + _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d \" -f 4) _debug record_id "$_record_id" _info "Successfully retrieved the record id for ACME challenge." else From d04434e3ecd286c2109afd313aecf31d2cc7ec49 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 1 Jul 2017 10:54:14 +0800 Subject: [PATCH 438/620] fix alias --- acme.sh | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/acme.sh b/acme.sh index fa969b0f..1f1071d1 100755 --- a/acme.sh +++ b/acme.sh @@ -4679,6 +4679,8 @@ _installalias() { _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" if [ "$_c_home" ]; then _setopt "$_envfile" "export LE_CONFIG_HOME" "=" "\"$LE_CONFIG_HOME\"" + else + _sed_i "/^export LE_CONFIG_HOME/d" "$_envfile" fi _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" @@ -4700,6 +4702,8 @@ _installalias() { _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" if [ "$_c_home" ]; then _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" + else + _sed_i "/^setenv LE_CONFIG_HOME/d" "$_cshfile" fi _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" _setopt "$_csh_profile" "source \"$_cshfile\"" @@ -4764,20 +4768,24 @@ install() { _info "Installing to $LE_WORKING_DIR" - if ! mkdir -p "$LE_WORKING_DIR"; then - _err "Can not create working dir: $LE_WORKING_DIR" - return 1 + if [ ! -d "$LE_WORKING_DIR" ]; then + if ! mkdir -p "$LE_WORKING_DIR"; then + _err "Can not create working dir: $LE_WORKING_DIR" + return 1 + fi + + chmod 700 "$LE_WORKING_DIR" fi - chmod 700 "$LE_WORKING_DIR" + if [ ! -d "$LE_CONFIG_HOME" ]; then + if ! mkdir -p "$LE_CONFIG_HOME"; then + _err "Can not create config dir: $LE_CONFIG_HOME" + return 1 + fi - if ! mkdir -p "$LE_CONFIG_HOME"; then - _err "Can not create config dir: $LE_CONFIG_HOME" - return 1 + chmod 700 "$LE_CONFIG_HOME" fi - chmod 700 "$LE_CONFIG_HOME" - cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" if [ "$?" != "0" ]; then From 63c6ed3fd06263a5ad8ebb2788807bda13237f42 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Sat, 1 Jul 2017 05:14:52 -0700 Subject: [PATCH 439/620] Fixes to follow coding standards. --- dnsapi/dns_duckdns.sh | 16 ++++++++-------- dnsapi/dns_namecom.sh | 32 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index cacf5a8c..95df4c21 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -7,7 +7,7 @@ # Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure must be used with acme.sh DuckDNS_API="https://www.duckdns.org/update" -API_Params="domains=$DuckDNS_domain&token=$DuckDNS_token" +API_Params="domains=$DuckDNS_Domain&token=$DuckDNS_Token" ######## Public functions ##################### @@ -17,23 +17,23 @@ dns_duckdns_add() { txtvalue=$2 # We'll extract the domain/username from full domain - DuckDNS_domain=$(printf "%s\n" "$fulldomain" | rev | cut -d . -f 3 | rev) + DuckDNS_Domain=$(echo $fulldomain | _lower_case | _egrep_o '.[^.]*.duckdns.org' | cut -d . -f 2) - if [ -z "$DuckDNS_domain" ]; then + if [ -z "$DuckDNS_Domain" ]; then _err "Error extracting the domain." return 1 fi - if [ -z "$DuckDNS_token" ]; then - DuckDNS_token="" + if [ -z "$DuckDNS_Token" ]; then + DuckDNS_Token="" _err "The token for your DuckDNS account is necessary." _err "You can look it up in your DuckDNS account." return 1 fi # Now save the credentials. - _saveaccountconf DuckDNS_domain "$DuckDNS_domain" - _saveaccountconf DuckDNS_token "$DuckDNS_token" + _saveaccountconf DuckDNS_Domain "$DuckDNS_Domain" + _saveaccountconf DuckDNS_Token "$DuckDNS_Token" # Unfortunately, DuckDNS does not seems to support lookup domain through API # So I assume your credentials (which are your domain and token) are correct @@ -86,6 +86,6 @@ _duckdns_rest() { return 1 fi - _debug response "$response" + _debug2 response "$response" return 0 } diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 2c5a5df4..15eae6c2 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -5,7 +5,7 @@ #Utilize name.com API to finish dns-01 verifications. ######## Public functions ##################### -namecom_api="https://api.name.com/api" +Namecom_API="https://api.name.com/api" #Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_namecom_add() { @@ -13,23 +13,23 @@ dns_namecom_add() { txtvalue=$2 # First we need name.com credentials. - if [ -z "$namecom_username" ]; then - namecom_username="" + if [ -z "$Namecom_Username" ]; then + Namecom_Username="" _err "Username for name.com is missing." _err "Please specify that in your environment variable." return 1 fi - if [ -z "$namecom_token" ]; then - namecom_token="" + if [ -z "$Namecom_Token" ]; then + Namecom_Token="" _err "API token for name.com is missing." _err "Please specify that in your environment variable." return 1 fi # Save them in configuration. - _saveaccountconf namecom_username "$namecom_username" - _saveaccountconf namecom_token "$namecom_token" + _saveaccountconf Namecom_Username "$Namecom_Username" + _saveaccountconf Namecom_Token "$Namecom_Token" # Login in using API _namecom_login @@ -45,7 +45,7 @@ dns_namecom_add() { _namecom_addtxt_json="{\"hostname\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":\"300\",\"priority\":\"10\"}" if _namecom_rest POST "dns/create/$_domain" "$_namecom_addtxt_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then + if [ "$retcode" ]; then _info "Successfully added TXT record, ready for validation." _namecom_logout return 0 @@ -75,7 +75,7 @@ dns_namecom_rm() { # Get the record id. if _namecom_rest GET "dns/list/$_domain"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then + if [ "$retcode" ]; then _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d \" -f 4) _debug record_id "$_record_id" _info "Successfully retrieved the record id for ACME challenge." @@ -90,7 +90,7 @@ dns_namecom_rm() { _namecom_rmtxt_json="{\"record_id\":\"$_record_id\"}" if _namecom_rest POST "dns/delete/$_domain" "$_namecom_rmtxt_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then + if [ "$retcode" ]; then _info "Successfully removed the TXT record." _namecom_logout return 0 @@ -111,9 +111,9 @@ _namecom_rest() { export _H1="Content-Type: application/json" export _H2="Api-Session-Token: $sessionkey" if [ "$method" != "GET" ]; then - response="$(_post "$data" "$namecom_api/$param" "" "$method")" + response="$(_post "$data" "$Namecom_API/$param" "" "$method")" else - response="$(_get "$namecom_api/$param")" + response="$(_get "$Namecom_API/$param")" fi if [ "$?" != "0" ]; then @@ -121,16 +121,16 @@ _namecom_rest() { return 1 fi - _debug response "$response" + _debug2 response "$response" return 0 } _namecom_login() { - namecom_login_json="{\"username\":\"$namecom_username\",\"api_token\":\"$namecom_token\"}" + namecom_login_json="{\"username\":\"$Namecom_Username\",\"api_token\":\"$Namecom_Token\"}" if _namecom_rest POST "login" "$namecom_login_json"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then + if [ "$retcode" ]; then _info "Successfully logged in. Fetching session token..." sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4) if [ ! -z "$sessionkey" ]; then @@ -150,7 +150,7 @@ _namecom_login() { _namecom_logout() { if _namecom_rest GET "logout"; then retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") - if [ ! -z "$retcode" ]; then + if [ "$retcode" ]; then _info "Successfully logged out." else _err "Error logging out." From 9aed1e2d17331e4c2eeb8ed9f48aa132bdbf07ae Mon Sep 17 00:00:00 2001 From: RaidenII Date: Sat, 1 Jul 2017 05:18:12 -0700 Subject: [PATCH 440/620] Argh. Double quotes. --- dnsapi/dns_duckdns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index 95df4c21..d6987352 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -17,7 +17,7 @@ dns_duckdns_add() { txtvalue=$2 # We'll extract the domain/username from full domain - DuckDNS_Domain=$(echo $fulldomain | _lower_case | _egrep_o '.[^.]*.duckdns.org' | cut -d . -f 2) + DuckDNS_Domain=$(echo "$fulldomain" | _lower_case | _egrep_o '.[^.]*.duckdns.org' | cut -d . -f 2) if [ -z "$DuckDNS_Domain" ]; then _err "Error extracting the domain." From ea722da3deecf510c64e53df7b7ec4abe8c38123 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 1 Jul 2017 20:31:42 +0800 Subject: [PATCH 441/620] add debug info --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 1f1071d1..76509af0 100755 --- a/acme.sh +++ b/acme.sh @@ -2999,9 +2999,9 @@ _on_issue_err() { fi #trigger the validation to flush the pending authz + _debug2 "_chk_vlist" "$_chk_vlist" if [ "$_chk_vlist" ]; then ( - _debug2 "_chk_vlist" "$_chk_vlist" _debug2 "start to deactivate authz" ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ') for ventry in $ventries; do @@ -3498,7 +3498,7 @@ issue() { if [ "$?" != "0" ]; then _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi dnsadded='1' @@ -3510,7 +3510,7 @@ issue() { _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _err "Please add the TXT records to the domains, and retry again." _clearup - _on_issue_err "$_post_hook" + _on_issue_err "$_post_hook" "$vlist" return 1 fi From 14d7bfdab2c3f16c64080aec0dccd0fc9437288c Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 1 Jul 2017 21:47:30 +0800 Subject: [PATCH 442/620] fix deactivate for lower rate limit --- acme.sh | 65 +++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/acme.sh b/acme.sh index 76509af0..6590a00a 100755 --- a/acme.sh +++ b/acme.sh @@ -1152,7 +1152,7 @@ _ss() { if _exists "ss"; then _debug "Using: ss" - ss -ntpl | grep ":$_port " + ss -ntpl 2>/dev/null | grep ":$_port " return 0 fi @@ -4479,26 +4479,51 @@ _deactivate() { _d_type="$2" _initpath - _d_i=0 - _d_max_retry=9 - while [ "$_d_i" -lt "$_d_max_retry" ]; do - _info "Deactivate: $_d_domain" - _d_i="$(_math $_d_i + 1)" + if ! __get_domain_new_authz "$_d_domain"; then + _err "Can not get domain new authz token." + return 1 + fi - if ! __get_domain_new_authz "$_d_domain"; then - _err "Can not get domain new authz token." - return 1 - fi + authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" + _debug "authzUri" "$authzUri" - authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" - _debug "authzUri" "$authzUri" + if [ "$code" ] && [ ! "$code" = '201' ]; then + _err "new-authz error: $response" + return 1 + fi - if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then - _err "new-authz error: $response" + entries="$(echo "$response" | _egrep_o '{ *"type":"[^"]*", *"status": *"valid", *"uri"[^}]*')" + if [ -z "$entries" ]; then + _info "No valid entries found." + if [ -z "$thumbprint" ]; then + thumbprint="$(__calc_account_thumbprint)" + fi + _debug "Trigger validation." + vtype="$VTYPE_HTTP" + entry="$(printf "%s\n" "$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 '"')" + _debug token "$token" - entry="$(printf "%s\n" "$response" | _egrep_o '{"type":"[^"]*","status":"valid","uri"[^}]*')" + uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" + _debug uri "$uri" + + keyauthorization="$token.$thumbprint" + _debug keyauthorization "$keyauthorization" + __trigger_validation "$uri" "$keyauthorization" + + fi + + _d_i=0 + _d_max_retry=$(echo "$entries" | wc -l) + while [ "$_d_i" -lt "$_d_max_retry" ]; do + _info "Deactivate: $_d_domain" + _d_i="$(_math $_d_i + 1)" + entry="$(echo "$entries" | sed -n "${_d_i}p")" _debug entry "$entry" if [ -z "$entry" ]; then @@ -4520,16 +4545,16 @@ _deactivate() { _info "Deactivate: $_vtype" - if ! _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}"; then + if _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then + _info "Deactivate: $_vtype success." + else _err "Can not deactivate $_vtype." - return 1 + break fi - _info "Deactivate: $_vtype success." - done _debug "$_d_i" - if [ "$_d_i" -lt "$_d_max_retry" ]; then + if [ "$_d_i" -eq "$_d_max_retry" ]; then _info "Deactivated success!" else _err "Deactivate failed." From 1be222f6ed23e5c793f7a6be834f5c96871d6ffe Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jul 2017 13:38:44 +0800 Subject: [PATCH 443/620] minor --- acme.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 6590a00a..95964984 100755 --- a/acme.sh +++ b/acme.sh @@ -4614,9 +4614,7 @@ _detect_profile() { fi fi - if [ ! -z "$DETECTED_PROFILE" ]; then - echo "$DETECTED_PROFILE" - fi + echo "$DETECTED_PROFILE" } _initconf() { From c4b2e5829e7ad66941c60e4aa146f227f7df8cb9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jul 2017 15:25:35 +0800 Subject: [PATCH 444/620] add always-force-new-domain-key. fix https://github.com/Neilpang/acme.sh/issues/914 --- acme.sh | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 95964984..e8e04e7c 100755 --- a/acme.sh +++ b/acme.sh @@ -1281,7 +1281,7 @@ createDomainKey() { _initpath "$domain" "$_cdl" - if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]); then + if [ ! -f "$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)" @@ -3148,7 +3148,7 @@ _regAccount() { return 1 fi if [ "$code" = '202' ]; then - _info "Update success." + _info "Update account tos info success." CA_KEY_HASH="$(__calcAccountKeyHash)" _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" @@ -3355,7 +3355,7 @@ issue() { else _key=$(_readdomainconf Le_Keylength) _debug "Read key length:$_key" - if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ]; then + if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ] || [ "$Le_ForceNewDomainKey" = "1" ]; then if ! createDomainKey "$_main_domain" "$_key_length"; then _err "Create domain key error." _clearup @@ -3885,6 +3885,12 @@ issue() { _cleardomainconf Le_Listen_V4 fi + if [ "$Le_ForceNewDomainKey" = "1" ]; then + _savedomainconf "Le_ForceNewDomainKey" "$Le_ForceNewDomainKey" + else + _cleardomainconf Le_ForceNewDomainKey + fi + Le_NextRenewTime=$(_math "$Le_CertCreateTime" + "$Le_RenewalDays" \* 24 \* 60 \* 60) Le_NextRenewTimeStr=$(_time2str "$Le_NextRenewTime") @@ -5026,6 +5032,7 @@ Parameters: --renew-hook Command to be run once for each successfully renewed certificate. --deploy-hook The hook file to deploy cert --ocsp-must-staple, --ocsp Generate ocsp must Staple extension. + --always-force-new-domain-key Generate new domain key when renewal. Otherwise, the domain key is not changed by default. --auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future. --listen-v4 Force standalone/tls server to listen at ipv4. --listen-v6 Force standalone/tls server to listen at ipv6. @@ -5506,6 +5513,14 @@ _process() { --ocsp-must-staple | --ocsp) Le_OCSP_Staple="1" ;; + --always-force-new-domain-key) + if [ -z "$2" ] || _startswith "$2" "-"; then + Le_ForceNewDomainKey=1 + else + Le_ForceNewDomainKey="$2" + shift + fi + ;; --log | --logfile) _log="1" _logfile="$2" From 422dd1fa4f57c977ccb4083be9463500b544d293 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jul 2017 17:02:54 +0800 Subject: [PATCH 445/620] Implement deactivate account: --deactivate-account --- acme.sh | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e8e04e7c..99c83a04 100755 --- a/acme.sh +++ b/acme.sh @@ -366,6 +366,7 @@ _hasfield() { return 1 #not contains } +# str index [sep] _getfield() { _str="$1" _findex="$2" @@ -3127,7 +3128,7 @@ _regAccount() { _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" _debug "_accUri" "$_accUri" - + _savecaconf "ACCOUNT_URL" "$_accUri" _tos="$(echo "$responseHeaders" | grep "^Link:.*rel=\"terms-of-service\"" | _head_n 1 | _egrep_o "<.*>" | tr -d '<>')" _debug "_tos" "$_tos" if [ -z "$_tos" ]; then @@ -3153,6 +3154,9 @@ _regAccount() { CA_KEY_HASH="$(__calcAccountKeyHash)" _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" _savecaconf CA_KEY_HASH "$CA_KEY_HASH" + elif [ "$code" = '403' ]; then + _err "It seems that the account key is already deactivated, please use a new account key." + return 1 else _err "Update account error." return 1 @@ -3165,6 +3169,71 @@ _regAccount() { } + +#Implement deactivate account +deactivateaccount() { + _initpath + + if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then + mkdir -p "$CA_DIR" + _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 + mkdir -p "$CA_DIR" + _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 _send_signed_request "$_accUri" "{\"resource\": \"reg\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then + _info "Deactivate account success for $_accUri." + _accid=$(echo "$response" | _egrep_o "\"id\" *: *[^,]*," | cut -d : -f 2 | tr -d ' ,') + elif [ "$code" = "403" ]; then + _info "The account is already deactivated." + _accid=$(_getfield "$_accUri" "999" "/") + else + _err "Deactivate: account failed for $_accUri." + return 1 + fi + + _debug "Account id: $_accid" + if [ "$_accid" ]; then + _deactivated_account_path="$CA_DIR/deactivated/$_accid" + _debug _deactivated_account_path "$_deactivated_account_path" + if mkdir -p "$_deactivated_account_path"; then + _info "Moving deactivated account info to $_deactivated_account_path/" + mv "$CA_CONF" "$_deactivated_account_path/" + mv "$ACCOUNT_JSON_PATH" "$_deactivated_account_path/" + mv "$ACCOUNT_KEY_PATH" "$_deactivated_account_path/" + else + _err "Can not create dir: $_deactivated_account_path, try to remove the deactivated account key." + rm -f "$CA_CONF" + rm -f "$ACCOUNT_JSON_PATH" + rm -f "$ACCOUNT_KEY_PATH" + fi + fi +} + # domain folder file _findHook() { _hookdomain="$1" @@ -4972,6 +5041,7 @@ Commands: --toPkcs8 Convert to pkcs8 format. --update-account Update account info. --register-account Register account key. + --deactivate-account Deactivate the account. --create-account-key Create an account private key, professional use. --create-domain-key Create an domain private key, professional use. --createCSR, -ccsr Create CSR , professional use. @@ -5252,6 +5322,9 @@ _process() { --registeraccount | --register-account) _CMD="registeraccount" ;; + --deactivate-account) + _CMD="deactivateaccount" + ;; --domain | -d) _dvalue="$2" @@ -5667,6 +5740,9 @@ _process() { updateaccount) updateaccount ;; + deactivateaccount) + deactivateaccount + ;; list) list "$_listraw" ;; From a71eba07a1530aba3d6c2a454e40f1436a64996e Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jul 2017 18:05:55 +0800 Subject: [PATCH 446/620] minor, fix resource name --- acme.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 99c83a04..41818c75 100755 --- a/acme.sh +++ b/acme.sh @@ -2197,7 +2197,9 @@ _initAPI() { export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz" export ACME_NEW_ORDER="https://acme-v01.api.letsencrypt.org/acme/new-cert" + export ACME_NEW_ORDER_RES="new-cert" export ACME_NEW_ACCOUNT="https://acme-v01.api.letsencrypt.org/acme/new-reg" + export ACME_NEW_ACCOUNT_RES="new-reg" export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert" fi @@ -2217,16 +2219,22 @@ _initAPI() { export ACME_NEW_AUTHZ ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) + ACME_NEW_ORDER_RES="new-cert" if [ -z "$ACME_NEW_ORDER" ]; then ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3) + ACME_NEW_ORDER_RES="new-order" fi export ACME_NEW_ORDER + export ACME_NEW_ORDER_RES ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) + ACME_NEW_ACCOUNT_RES="new-reg" if [ -z "$ACME_NEW_ACCOUNT" ]; then ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3) + ACME_NEW_ACCOUNT_RES="new-account" fi export ACME_NEW_ACCOUNT + export ACME_NEW_ACCOUNT_RES ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_REVOKE_CERT @@ -3098,7 +3106,7 @@ _regAccount() { fi _initAPI _updateTos="" - _reg_res="new-reg" + _reg_res="$ACME_NEW_ACCOUNT_RES" while true; do _debug AGREEMENT "$AGREEMENT" @@ -3830,7 +3838,7 @@ issue() { _info "Verify finished, start to sign." der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" - if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then + if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 From 1bbc33a0cf2d46067c6d0901e8c94aa7f7749ebf Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jul 2017 18:24:55 +0800 Subject: [PATCH 447/620] minor fix CA_DIR --- acme.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 41818c75..4d272750 100755 --- a/acme.sh +++ b/acme.sh @@ -3082,14 +3082,13 @@ _regAccount() { _initpath _reg_length="$1" + mkdir -p "$CA_DIR" if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then - mkdir -p "$CA_DIR" _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 - mkdir -p "$CA_DIR" _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" fi @@ -3183,13 +3182,11 @@ deactivateaccount() { _initpath if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then - mkdir -p "$CA_DIR" _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 - mkdir -p "$CA_DIR" _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" fi From 6b185d20c0be746632fa621a0fee762b65ea9cf9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 2 Jul 2017 18:40:11 +0800 Subject: [PATCH 448/620] fix format --- acme.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 4d272750..fa090cdf 100755 --- a/acme.sh +++ b/acme.sh @@ -1282,7 +1282,7 @@ createDomainKey() { _initpath "$domain" "$_cdl" - if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]) || [ "$Le_ForceNewDomainKey" = "1" ] ; then + if [ ! -f "$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)" @@ -3176,7 +3176,6 @@ _regAccount() { } - #Implement deactivate account deactivateaccount() { _initpath From 2e602ef6b078543c79b9c86a179ed039bad30ce6 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Sun, 2 Jul 2017 04:45:07 -0700 Subject: [PATCH 449/620] Added ret value verification. --- dnsapi/dns_namecom.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 15eae6c2..146db4f6 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -32,7 +32,9 @@ dns_namecom_add() { _saveaccountconf Namecom_Token "$Namecom_Token" # Login in using API - _namecom_login + if ! _namecom_login; then + return 1 + fi # Find domain in domain list. if ! _namecom_get_root "$fulldomain"; then @@ -63,7 +65,9 @@ dns_namecom_rm() { fulldomain=$1 txtvalue=$2 - _namecom_login + if ! _namecom_login; then + return 1 + fi # Find domain in domain list. if ! _namecom_get_root "$fulldomain"; then From 1a504118e56dd73ae1fe7b2fb16b58fd76e68765 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Sun, 2 Jul 2017 04:55:06 -0700 Subject: [PATCH 450/620] Updated DNS API support list. --- README.md | 3 ++- dnsapi/README.md | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b6b03ae..7780b9ab 100644 --- a/README.md +++ b/README.md @@ -334,7 +334,8 @@ You don't have to do anything manually! 1. Dynu API (https://www.dynu.com) 1. DNSimple API 1. NS1.com API - +1. DuckDNS.org API +1. Name.com API And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 5dca829a..7584b31e 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -505,6 +505,37 @@ 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 must be used when issuing certs: +``` +acme.sh --insecure --issue --dns dns_duckdns -d mydomain.duckdns.org +``` + +Also, DuckDNS uses the domain name as username for recording changing, so the +account file will always store the lastly used domain name. + +For issues, please report to https://github.com/raidenii/acme.sh/issues. + +## 28. Use Name.com API + +``` +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. + # Use custom API If your API is not supported yet, you can write your own DNS API. From 3002f6dfd5f2324fba4ee9fef1cf8ee8b896b8a9 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Sun, 2 Jul 2017 06:02:44 -0700 Subject: [PATCH 451/620] Updated README.md for Name.com API application. --- dnsapi/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index 7584b31e..e956b355 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -525,6 +525,10 @@ For issues, please report to https://github.com/raidenii/acme.sh/issues. ## 28. Use Name.com API ``` +You'll need to fill out the form at https://www.name.com/reseller/apply to apply +for API username and token. +``` + export Namecom_Username="testuser" export Namecom_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ``` From 333090a96733f6701453ab3f5a1281ed99ff1ab5 Mon Sep 17 00:00:00 2001 From: RaidenII Date: Sun, 2 Jul 2017 06:38:25 -0700 Subject: [PATCH 452/620] Fix README.md for DNS API. --- dnsapi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index e956b355..57c360b7 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -524,16 +524,16 @@ For issues, please report to https://github.com/raidenii/acme.sh/issues. ## 28. Use Name.com API -``` You'll need to fill out the form at https://www.name.com/reseller/apply to apply for API username and token. -``` +``` export Namecom_Username="testuser" export Namecom_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ``` And now you can issue certs with: + ``` acme.sh --issue --dns dns_namecom -d example.com -d www.example.com ``` From 6c3430b6e592b0dad0783c4daee0ee692d5e0484 Mon Sep 17 00:00:00 2001 From: 2globalnomads Date: Sun, 2 Jul 2017 23:24:14 +0400 Subject: [PATCH 453/620] Wrote missing cpanel.sh This script I wrote works for me on GoDaddy, but I don't have any other hosting services or cpanel version to test it. Hope it's better than nothing for you. Thanks for your great script! Cheers, Santeri --- deploy/cpanel.sh | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/deploy/cpanel.sh b/deploy/cpanel.sh index bf1332ff..6ab012a3 100644 --- a/deploy/cpanel.sh +++ b/deploy/cpanel.sh @@ -1,8 +1,9 @@ -#!/usr/bin/env sh - -#Here is the script to deploy the cert to your cpanel account by the cpanel APIs. - -#returns 0 means success, otherwise error. +#!/bin/bash +# Here is the script to deploy the cert to your cpanel using the cpanel API. +# Uses command line uapi. Cpanel username is needed only when run as root. +# Returns 0 when success, otherwise error. +# Written by Santeri Kannisto +# Public domain, 2017 #export DEPLOY_CPANEL_USER=myusername #export DEPLOY_CPANEL_PASSWORD=PASSWORD @@ -10,6 +11,7 @@ ######## Public functions ##################### #domain keyfile certfile cafile fullchain + cpanel_deploy() { _cdomain="$1" _ckey="$2" @@ -23,7 +25,33 @@ cpanel_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - _err "Not implemented yet" - return 1 + # read cert and key files and urlencode both + _certstr=`cat "$_ccert"` + _keystr=`cat "$_ckey"` + _cert=$(php -r "echo urlencode(\"$_certstr\");") + _key=$(php -r "echo urlencode(\"$_keystr\");") + + _debug _cert "$_cert" + _debug _key "$_key" + + if [[ $EUID -eq 0 ]] + then + _opt="--user=$DEPLOY_CPANEL_USER SSL install_ssl" + else + _opt="SSL install_ssl" + fi + + _debug _opt "$_opt" + + response=$(uapi $_opt domain="$_cdommain" cert="$_cert" key="$_key") + + if [ $? -ne 0 ] + then + _err "Error in deploying certificate:" + _err "$response" + return 1 + fi + _debug response "$response" + _info "Certificate successfully deployed" } From 6963f3880d1e06211bc8c631154868efa8c6bafb Mon Sep 17 00:00:00 2001 From: RaidenII Date: Mon, 3 Jul 2017 03:28:28 -0700 Subject: [PATCH 454/620] Fixes the get_root function so that when domain doesn't exist it will correctly return error. --- dnsapi/dns_namecom.sh | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index 146db4f6..fae56d65 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -168,21 +168,26 @@ _namecom_get_root() { i=2 p=1 - if _namecom_rest GET "domain/list"; then - while true; do - host=$(printf "%s" "$domain" | cut -d . -f $i-100) - if [ -z "$host" ]; then - return 1 - fi - - if _contains "$response" "$host"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - _domain="$host" - return 0 - fi - p=$i - i=$(_math "$i" + 1) - done + if ! _namecom_rest GET "domain/list"; then + return 1 fi + + # Need to exclude the last field (tld) + numfields=$(echo "$domain" | _egrep_o "\." | wc -l) + while [ $i -le $numfields ]; do + host=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug host "$host" + if [ -z "$host" ]; then + return 1 + fi + + if _contains "$response" "$host"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$host" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done return 1 } From 7b32bbfc266015b69a3dfc316e03097add2bdd3e Mon Sep 17 00:00:00 2001 From: RaidenII Date: Mon, 3 Jul 2017 08:22:16 -0400 Subject: [PATCH 455/620] Fix for SC2086. --- dnsapi/dns_namecom.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_namecom.sh b/dnsapi/dns_namecom.sh index fae56d65..3af8bf4c 100755 --- a/dnsapi/dns_namecom.sh +++ b/dnsapi/dns_namecom.sh @@ -174,7 +174,7 @@ _namecom_get_root() { # Need to exclude the last field (tld) numfields=$(echo "$domain" | _egrep_o "\." | wc -l) - while [ $i -le $numfields ]; do + while [ $i -le "$numfields" ]; do host=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug host "$host" if [ -z "$host" ]; then From 5f8b60a0e5653595689703fe68d9b3e99d14d1ab Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 4 Jul 2017 08:23:09 +0800 Subject: [PATCH 456/620] fix https://github.com/Neilpang/acme.sh/issues/926 don't trigger validation for dns manually mode --- acme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acme.sh b/acme.sh index fa090cdf..ef468a45 100755 --- a/acme.sh +++ b/acme.sh @@ -3543,11 +3543,11 @@ issue() { if [ "$d_api" ]; then _info "Found domain api file: $d_api" else - _err "Add the following TXT record:" - _err "Domain: '$(__green "$txtdomain")'" - _err "TXT value: '$(__green "$txt")'" - _err "Please be aware that you prepend _acme-challenge. before your domain" - _err "so the resulting subdomain will be: $txtdomain" + _info "$(__red "Add the following TXT record:")" + _info "$(__red "Domain: '$(__green "$txtdomain")'")" + _info "$(__red "TXT value: '$(__green "$txt")'")" + _info "$(__red "Please be aware that you prepend _acme-challenge. before your domain")" + _info "$(__red "so the resulting subdomain will be: $txtdomain")" continue fi @@ -3583,7 +3583,7 @@ issue() { _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." _err "Please add the TXT records to the domains, and retry again." _clearup - _on_issue_err "$_post_hook" "$vlist" + _on_issue_err "$_post_hook" return 1 fi From 81772fb703af18f7d7f8d7b7b7e3a6d61be14554 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 4 Jul 2017 09:08:54 +0800 Subject: [PATCH 457/620] minor, fix format --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index ef468a45..35842f4e 100755 --- a/acme.sh +++ b/acme.sh @@ -3544,10 +3544,10 @@ issue() { _info "Found domain api file: $d_api" else _info "$(__red "Add the following TXT record:")" - _info "$(__red "Domain: '$(__green "$txtdomain")'")" - _info "$(__red "TXT value: '$(__green "$txt")'")" - _info "$(__red "Please be aware that you prepend _acme-challenge. before your domain")" - _info "$(__red "so the resulting subdomain will be: $txtdomain")" + _info "$(__red "Domain: '$(__green "$txtdomain")'")" + _info "$(__red "TXT value: '$(__green "$txt")'")" + _info "$(__red "Please be aware that you prepend _acme-challenge. before your domain")" + _info "$(__red "so the resulting subdomain will be: $txtdomain")" continue fi From 72fcf5ab85779aca28db1f4057e63d4e9ea850d4 Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Fri, 7 Jul 2017 09:51:43 -0500 Subject: [PATCH 458/620] Add 'dns_dyn' DNS challenge validation script for Dyn Managed DNS API --- dnsapi/README.md | 33 +++++ dnsapi/dns_dyn.sh | 340 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 373 insertions(+) create mode 100644 dnsapi/dns_dyn.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index 57c360b7..41f89a88 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -540,6 +540,39 @@ 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. + + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_dyn.sh b/dnsapi/dns_dyn.sh new file mode 100644 index 00000000..d3998809 --- /dev/null +++ b/dnsapi/dns_dyn.sh @@ -0,0 +1,340 @@ +#!/usr/bin/env sh +# +# Dyn.com Domain API +# +# Author: Gerd Naschenweng +# https://github.com/magicdude4eva +# +# Dyn Managed DNS API +# https://help.dyn.com/dns-api-knowledge-base/ +# +# It is recommended to add a "Dyn Managed DNS" user specific for API access. +# The "Zones & Records Permissions" required by this script are: +# -- +# RecordAdd +# RecordUpdate +# RecordDelete +# RecordGet +# ZoneGet +# ZoneAddNode +# ZoneRemoveNode +# ZonePublish +# -- +# +# Pass credentials before "acme.sh --issue --dns dns_dyn ..." +# -- +# export DYN_Customer="customer" +# export DYN_Username="apiuser" +# export DYN_Password="secret" +# -- + +DYN_API="https://api.dynect.net/REST" + +#REST_API +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "Challenge-code" +dns_dyn_add() { + fulldomain="$1" + txtvalue="$2" + + DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}" + DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}" + DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}" + if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then + DYN_Customer="" + DYN_Username="" + DYN_Password="" + _err "You must export variables: DYN_Customer, DYN_Username and DYN_Password" + return 1 + fi + + #save the config variables to the account conf file. + _saveaccountconf_mutable DYN_Customer "$DYN_Customer" + _saveaccountconf_mutable DYN_Username "$DYN_Username" + _saveaccountconf_mutable DYN_Password "$DYN_Password" + + if ! _dyn_get_authtoken; then + return 1 + fi + + if [ -z "$_dyn_authtoken" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_zone; then + _dyn_end_session + return 1 + fi + + if ! _dyn_add_record; then + _dyn_end_session + return 1 + fi + + if ! _dyn_publish_zone; then + _dyn_end_session + return 1 + fi + + _dyn_end_session + + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_dyn_rm() { + fulldomain="$1" + txtvalue="$2" + + DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}" + DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}" + DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}" + if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then + DYN_Customer="" + DYN_Username="" + DYN_Password="" + _err "You must export variables: DYN_Customer, DYN_Username and DYN_Password" + return 1 + fi + + if ! _dyn_get_authtoken; then + return 1 + fi + + if [ -z "$_dyn_authtoken" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_zone; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_record_id; then + _dyn_end_session + return 1 + fi + + if [ -z "$_dyn_record_id" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_rm_record; then + _dyn_end_session + return 1 + fi + + if ! _dyn_publish_zone; then + _dyn_end_session + return 1 + fi + + _dyn_end_session + + return 0 +} + +#################### Private functions below ################################## + +#get Auth-Token +_dyn_get_authtoken() { + + _info "Start Dyn API Session" + + data="{\"customer_name\":\"$DYN_Customer\", \"user_name\":\"$DYN_Username\", \"password\":\"$DYN_Password\"}" + dyn_url="$DYN_API/Session/" + method="POST" + + _debug data "$data" + _debug dyn_url "$dyn_url" + + export _H1="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_authtoken="$(printf "%s\n" "$response" | _egrep_o '"token" *: *"[^"]*' | head -n 1 | sed 's#^"token" *: *"##')" + _info "Token received" + _debug _dyn_authtoken "$_dyn_authtoken" + return 0 + fi + + _dyn_authtoken="" + _err "get token failed" + return 1 +} + +#fulldomain=_acme-challenge.www.domain.com +#returns +# _dyn_zone=domain.com +_dyn_get_zone() { + i=2 + while true; do + domain="$(printf "%s" "$fulldomain" | cut -d . -f "$i-100")" + if [ -z "$domain" ]; then + break + fi + + dyn_url="$DYN_API/Zone/$domain/" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_get "$dyn_url" "" "")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + + _debug dyn_url "$dyn_url" + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_zone="$domain" + return 0 + fi + i=$(_math "$i" + 1) + done + + _dyn_zone="" + _err "get zone failed" + return 1 +} + +#add TXT record +_dyn_add_record() { + + _info "Adding TXT record" + + data="{\"rdata\":{\"txtdata\":\"$txtvalue\"},\"ttl\":\"300\"}" + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/" + method="POST" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "TXT Record successfully added" + return 0 + fi + + _err "add TXT record failed" + return 1 +} + +#publish the zone +_dyn_publish_zone() { + + _info "Publishing zone" + + data="{\"publish\":\"true\"}" + dyn_url="$DYN_API/Zone/$_dyn_zone/" + method="PUT" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "Zone published" + return 0 + fi + + _err "publish zone failed" + return 1 +} + +#get record_id of TXT record so we can delete the record +_dyn_get_record_id() { + + _info "Getting record_id of TXT record" + + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_get "$dyn_url" "" "")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_record_id="$(printf "%s\n" "$response" | _egrep_o "\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/[^\"]*" | head -n 1 | sed "s#^\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/##")" + _debug _dyn_record_id "$_dyn_record_id" + return 0 + fi + + _dyn_record_id="" + _err "getting record_id failed" + return 1 +} + +#delete TXT record +_dyn_rm_record() { + + _info "Deleting TXT record" + + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/$_dyn_record_id/" + method="DELETE" + + _debug dyn_url "$dyn_url" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "TXT record successfully deleted" + return 0 + fi + + _err "delete TXT record failed" + return 1 +} + +#logout +_dyn_end_session() { + + _info "End Dyn API Session" + + dyn_url="$DYN_API/Session/" + method="DELETE" + + _debug dyn_url "$dyn_url" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "" "$dyn_url" "" "$method")" + + _debug response "$response" + + _dyn_authtoken="" + return 0 +} + From 0aba5dc8de914cae7256cacdc189e2f31e491b74 Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Fri, 7 Jul 2017 10:22:20 -0500 Subject: [PATCH 459/620] dns_dyn.sh, remove empty line at end --- dnsapi/dns_dyn.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/dnsapi/dns_dyn.sh b/dnsapi/dns_dyn.sh index d3998809..c0dc1c74 100644 --- a/dnsapi/dns_dyn.sh +++ b/dnsapi/dns_dyn.sh @@ -337,4 +337,3 @@ _dyn_end_session() { _dyn_authtoken="" return 0 } - From 528d2f29d34a3d9e417a91f02ffde35cc63b2476 Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Fri, 7 Jul 2017 10:33:24 -0500 Subject: [PATCH 460/620] dns_dyn.sh, remove trailing spaces at end of line --- dnsapi/dns_dyn.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_dyn.sh b/dnsapi/dns_dyn.sh index c0dc1c74..e1120018 100644 --- a/dnsapi/dns_dyn.sh +++ b/dnsapi/dns_dyn.sh @@ -240,7 +240,7 @@ _dyn_publish_zone() { _info "Publishing zone" - data="{\"publish\":\"true\"}" + data="{\"publish\":\"true\"}" dyn_url="$DYN_API/Zone/$_dyn_zone/" method="PUT" From 13a8c309f5b4de09ac263a5ad2ae0cbeed044f30 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 8 Jul 2017 09:20:12 +0800 Subject: [PATCH 461/620] fix new shellcheck errors --- .travis.yml | 2 +- dnsapi/dns_aws.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7f7e120c..2ba02b9c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,7 @@ script: - if [ "$TRAVIS_OS_NAME" = "linux" ]; then ~/shfmt -l -w -i 2 . ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck **/*.sh && echo "shellcheck OK" ; 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 - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 800c3d09..40782573 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -208,7 +208,7 @@ aws_rest() { kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)" _debug2 kServiceH "$kServiceH" - kSigningH="$(printf "aws4_request%s" | _hmac "$Hash" "$kServiceH" hex)" + kSigningH="$(printf "%s" "aws4_request" | _hmac "$Hash" "$kServiceH" hex)" _debug2 kSigningH "$kSigningH" signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)" From 0b797f596409683f90ed4fd1354f4027d3bf7b3c Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 8 Jul 2017 14:12:31 +0800 Subject: [PATCH 462/620] fix new shellcheck error --- dnsapi/dns_infoblox.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 06ac87ec..4cbb2146 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -41,10 +41,10 @@ dns_infoblox_add() { export _H2="Authorization: Basic $Infoblox_CredsEncoded" ## Add the challenge record to the Infoblox grid member - result=$(_post "" "$baseurlnObject" "" "POST") + result="$(_post "" "$baseurlnObject" "" "POST")" ## Let's see if we get something intelligible back from the unit - if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then + if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then _info "Successfully created the txt record" return 0 else @@ -66,7 +66,7 @@ dns_infoblox_rm() { _debug txtvalue "$txtvalue" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded="$(printf "%b" "$Infoblox_Creds" | _base64)" ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -74,17 +74,17 @@ dns_infoblox_rm() { ## Does the record exist? Let's check. baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View&_return_type=xml-pretty" - result=$(_get "$baseurlnObject") + result="$(_get "$baseurlnObject")" ## Let's see if we get something intelligible back from the grid - if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then + if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then ## Extract the object reference - objRef=$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View") + objRef="$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" ## Delete them! All the stale records! - rmResult=$(_post "" "$objRmUrl" "" "DELETE") + rmResult="$(_post "" "$objRmUrl" "" "DELETE")" ## Let's see if that worked - if echo "$rmResult" | egrep "record:txt/.*:.*/$Infoblox_View"; then + if [ "$(echo "$rmResult" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then _info "Successfully deleted $objRef" return 0 else From 200287254bce74e8deb1f28da611de432015c837 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 8 Jul 2017 17:25:01 +0800 Subject: [PATCH 463/620] add deactivate-account --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 8f363852..5849eb46 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,6 +44,7 @@ RUN for verb in help \ create-domain-key \ createCSR \ deactivate \ + deactivate-account \ ; do \ printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \ ; done From babe884b7c7a3b599defc37ff1e392d4c61bd6ad Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Sat, 8 Jul 2017 06:39:18 -0500 Subject: [PATCH 464/620] Replace 'head -n' with the '_head_n' function --- dnsapi/dns_dyn.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_dyn.sh b/dnsapi/dns_dyn.sh index e1120018..024e0a38 100644 --- a/dnsapi/dns_dyn.sh +++ b/dnsapi/dns_dyn.sh @@ -156,13 +156,13 @@ _dyn_get_authtoken() { export _H1="Content-Type: application/json" response="$(_post "$data" "$dyn_url" "" "$method")" - sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" _debug response "$response" _debug sessionstatus "$sessionstatus" if [ "$sessionstatus" = "success" ]; then - _dyn_authtoken="$(printf "%s\n" "$response" | _egrep_o '"token" *: *"[^"]*' | head -n 1 | sed 's#^"token" *: *"##')" + _dyn_authtoken="$(printf "%s\n" "$response" | _egrep_o '"token" *: *"[^"]*' | _head_n 1 | sed 's#^"token" *: *"##')" _info "Token received" _debug _dyn_authtoken "$_dyn_authtoken" return 0 @@ -190,7 +190,7 @@ _dyn_get_zone() { export _H2="Content-Type: application/json" response="$(_get "$dyn_url" "" "")" - sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" _debug dyn_url "$dyn_url" _debug response "$response" @@ -221,7 +221,7 @@ _dyn_add_record() { export _H2="Content-Type: application/json" response="$(_post "$data" "$dyn_url" "" "$method")" - sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" _debug response "$response" _debug sessionstatus "$sessionstatus" @@ -248,7 +248,7 @@ _dyn_publish_zone() { export _H2="Content-Type: application/json" response="$(_post "$data" "$dyn_url" "" "$method")" - sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" _debug response "$response" _debug sessionstatus "$sessionstatus" @@ -273,13 +273,13 @@ _dyn_get_record_id() { export _H2="Content-Type: application/json" response="$(_get "$dyn_url" "" "")" - sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" _debug response "$response" _debug sessionstatus "$sessionstatus" if [ "$sessionstatus" = "success" ]; then - _dyn_record_id="$(printf "%s\n" "$response" | _egrep_o "\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/[^\"]*" | head -n 1 | sed "s#^\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/##")" + _dyn_record_id="$(printf "%s\n" "$response" | _egrep_o "\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/[^\"]*" | _head_n 1 | sed "s#^\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/##")" _debug _dyn_record_id "$_dyn_record_id" return 0 fi @@ -303,7 +303,7 @@ _dyn_rm_record() { export _H2="Content-Type: application/json" response="$(_post "" "$dyn_url" "" "$method")" - sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | head -n 1 | sed 's#^"status" *: *"##')" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" _debug response "$response" _debug sessionstatus "$sessionstatus" From 9bd2d927559fce8fe393cfb935f96c7fd6fc8723 Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Sat, 8 Jul 2017 06:43:21 -0500 Subject: [PATCH 465/620] Update main README.md DNS API list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7780b9ab..5c306a59 100644 --- a/README.md +++ b/README.md @@ -336,6 +336,7 @@ You don't have to do anything manually! 1. NS1.com API 1. DuckDNS.org API 1. Name.com API +1. Dyn Managed DNS API And: From 42b2adc03ed35a54f6cb2a237dd37f0e498774f2 Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Fri, 7 Jul 2017 09:51:43 -0500 Subject: [PATCH 466/620] Add 'dns_dyn' DNS challenge validation script for Dyn Managed DNS API dns_dyn.sh, remove empty line at end dns_dyn.sh, remove trailing spaces at end of line Replace 'head -n' with the '_head_n' function Update main README.md DNS API list --- .travis.yml | 2 +- Dockerfile | 1 + README.md | 1 + dnsapi/README.md | 33 ++++ dnsapi/dns_aws.sh | 2 +- dnsapi/dns_dyn.sh | 339 +++++++++++++++++++++++++++++++++++++++++ dnsapi/dns_infoblox.sh | 16 +- 7 files changed, 384 insertions(+), 10 deletions(-) create mode 100644 dnsapi/dns_dyn.sh diff --git a/.travis.yml b/.travis.yml index 7f7e120c..2ba02b9c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,7 @@ script: - if [ "$TRAVIS_OS_NAME" = "linux" ]; then ~/shfmt -l -w -i 2 . ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck **/*.sh && echo "shellcheck OK" ; 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 - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi diff --git a/Dockerfile b/Dockerfile index 8f363852..5849eb46 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,6 +44,7 @@ RUN for verb in help \ create-domain-key \ createCSR \ deactivate \ + deactivate-account \ ; do \ printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \ ; done diff --git a/README.md b/README.md index 7780b9ab..5c306a59 100644 --- a/README.md +++ b/README.md @@ -336,6 +336,7 @@ You don't have to do anything manually! 1. NS1.com API 1. DuckDNS.org API 1. Name.com API +1. Dyn Managed DNS API And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 57c360b7..41f89a88 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -540,6 +540,39 @@ 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. + + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 800c3d09..40782573 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -208,7 +208,7 @@ aws_rest() { kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)" _debug2 kServiceH "$kServiceH" - kSigningH="$(printf "aws4_request%s" | _hmac "$Hash" "$kServiceH" hex)" + kSigningH="$(printf "%s" "aws4_request" | _hmac "$Hash" "$kServiceH" hex)" _debug2 kSigningH "$kSigningH" signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)" diff --git a/dnsapi/dns_dyn.sh b/dnsapi/dns_dyn.sh new file mode 100644 index 00000000..024e0a38 --- /dev/null +++ b/dnsapi/dns_dyn.sh @@ -0,0 +1,339 @@ +#!/usr/bin/env sh +# +# Dyn.com Domain API +# +# Author: Gerd Naschenweng +# https://github.com/magicdude4eva +# +# Dyn Managed DNS API +# https://help.dyn.com/dns-api-knowledge-base/ +# +# It is recommended to add a "Dyn Managed DNS" user specific for API access. +# The "Zones & Records Permissions" required by this script are: +# -- +# RecordAdd +# RecordUpdate +# RecordDelete +# RecordGet +# ZoneGet +# ZoneAddNode +# ZoneRemoveNode +# ZonePublish +# -- +# +# Pass credentials before "acme.sh --issue --dns dns_dyn ..." +# -- +# export DYN_Customer="customer" +# export DYN_Username="apiuser" +# export DYN_Password="secret" +# -- + +DYN_API="https://api.dynect.net/REST" + +#REST_API +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "Challenge-code" +dns_dyn_add() { + fulldomain="$1" + txtvalue="$2" + + DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}" + DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}" + DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}" + if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then + DYN_Customer="" + DYN_Username="" + DYN_Password="" + _err "You must export variables: DYN_Customer, DYN_Username and DYN_Password" + return 1 + fi + + #save the config variables to the account conf file. + _saveaccountconf_mutable DYN_Customer "$DYN_Customer" + _saveaccountconf_mutable DYN_Username "$DYN_Username" + _saveaccountconf_mutable DYN_Password "$DYN_Password" + + if ! _dyn_get_authtoken; then + return 1 + fi + + if [ -z "$_dyn_authtoken" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_zone; then + _dyn_end_session + return 1 + fi + + if ! _dyn_add_record; then + _dyn_end_session + return 1 + fi + + if ! _dyn_publish_zone; then + _dyn_end_session + return 1 + fi + + _dyn_end_session + + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_dyn_rm() { + fulldomain="$1" + txtvalue="$2" + + DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}" + DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}" + DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}" + if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then + DYN_Customer="" + DYN_Username="" + DYN_Password="" + _err "You must export variables: DYN_Customer, DYN_Username and DYN_Password" + return 1 + fi + + if ! _dyn_get_authtoken; then + return 1 + fi + + if [ -z "$_dyn_authtoken" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_zone; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_record_id; then + _dyn_end_session + return 1 + fi + + if [ -z "$_dyn_record_id" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_rm_record; then + _dyn_end_session + return 1 + fi + + if ! _dyn_publish_zone; then + _dyn_end_session + return 1 + fi + + _dyn_end_session + + return 0 +} + +#################### Private functions below ################################## + +#get Auth-Token +_dyn_get_authtoken() { + + _info "Start Dyn API Session" + + data="{\"customer_name\":\"$DYN_Customer\", \"user_name\":\"$DYN_Username\", \"password\":\"$DYN_Password\"}" + dyn_url="$DYN_API/Session/" + method="POST" + + _debug data "$data" + _debug dyn_url "$dyn_url" + + export _H1="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_authtoken="$(printf "%s\n" "$response" | _egrep_o '"token" *: *"[^"]*' | _head_n 1 | sed 's#^"token" *: *"##')" + _info "Token received" + _debug _dyn_authtoken "$_dyn_authtoken" + return 0 + fi + + _dyn_authtoken="" + _err "get token failed" + return 1 +} + +#fulldomain=_acme-challenge.www.domain.com +#returns +# _dyn_zone=domain.com +_dyn_get_zone() { + i=2 + while true; do + domain="$(printf "%s" "$fulldomain" | cut -d . -f "$i-100")" + if [ -z "$domain" ]; then + break + fi + + dyn_url="$DYN_API/Zone/$domain/" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_get "$dyn_url" "" "")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug dyn_url "$dyn_url" + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_zone="$domain" + return 0 + fi + i=$(_math "$i" + 1) + done + + _dyn_zone="" + _err "get zone failed" + return 1 +} + +#add TXT record +_dyn_add_record() { + + _info "Adding TXT record" + + data="{\"rdata\":{\"txtdata\":\"$txtvalue\"},\"ttl\":\"300\"}" + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/" + method="POST" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "TXT Record successfully added" + return 0 + fi + + _err "add TXT record failed" + return 1 +} + +#publish the zone +_dyn_publish_zone() { + + _info "Publishing zone" + + data="{\"publish\":\"true\"}" + dyn_url="$DYN_API/Zone/$_dyn_zone/" + method="PUT" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "Zone published" + return 0 + fi + + _err "publish zone failed" + return 1 +} + +#get record_id of TXT record so we can delete the record +_dyn_get_record_id() { + + _info "Getting record_id of TXT record" + + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_get "$dyn_url" "" "")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_record_id="$(printf "%s\n" "$response" | _egrep_o "\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/[^\"]*" | _head_n 1 | sed "s#^\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/##")" + _debug _dyn_record_id "$_dyn_record_id" + return 0 + fi + + _dyn_record_id="" + _err "getting record_id failed" + return 1 +} + +#delete TXT record +_dyn_rm_record() { + + _info "Deleting TXT record" + + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/$_dyn_record_id/" + method="DELETE" + + _debug dyn_url "$dyn_url" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "TXT record successfully deleted" + return 0 + fi + + _err "delete TXT record failed" + return 1 +} + +#logout +_dyn_end_session() { + + _info "End Dyn API Session" + + dyn_url="$DYN_API/Session/" + method="DELETE" + + _debug dyn_url "$dyn_url" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "" "$dyn_url" "" "$method")" + + _debug response "$response" + + _dyn_authtoken="" + return 0 +} diff --git a/dnsapi/dns_infoblox.sh b/dnsapi/dns_infoblox.sh index 06ac87ec..4cbb2146 100644 --- a/dnsapi/dns_infoblox.sh +++ b/dnsapi/dns_infoblox.sh @@ -41,10 +41,10 @@ dns_infoblox_add() { export _H2="Authorization: Basic $Infoblox_CredsEncoded" ## Add the challenge record to the Infoblox grid member - result=$(_post "" "$baseurlnObject" "" "POST") + result="$(_post "" "$baseurlnObject" "" "POST")" ## Let's see if we get something intelligible back from the unit - if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then + if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then _info "Successfully created the txt record" return 0 else @@ -66,7 +66,7 @@ dns_infoblox_rm() { _debug txtvalue "$txtvalue" ## Base64 encode the credentials - Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) + Infoblox_CredsEncoded="$(printf "%b" "$Infoblox_Creds" | _base64)" ## Construct the HTTP Authorization header export _H1="Accept-Language:en-US" @@ -74,17 +74,17 @@ dns_infoblox_rm() { ## Does the record exist? Let's check. baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View&_return_type=xml-pretty" - result=$(_get "$baseurlnObject") + result="$(_get "$baseurlnObject")" ## Let's see if we get something intelligible back from the grid - if echo "$result" | egrep "record:txt/.*:.*/$Infoblox_View"; then + if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then ## Extract the object reference - objRef=$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View") + objRef="$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" ## Delete them! All the stale records! - rmResult=$(_post "" "$objRmUrl" "" "DELETE") + rmResult="$(_post "" "$objRmUrl" "" "DELETE")" ## Let's see if that worked - if echo "$rmResult" | egrep "record:txt/.*:.*/$Infoblox_View"; then + if [ "$(echo "$rmResult" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then _info "Successfully deleted $objRef" return 0 else From 3bf2e89a1a9f68188264aa7cbf0f1b2e17400566 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 21:35:22 +0300 Subject: [PATCH 467/620] add pdd.yandex.ru dns api --- dnsapi/dns_yandex.sh | 69 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100755 dnsapi/dns_yandex.sh diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh new file mode 100755 index 00000000..db38eb52 --- /dev/null +++ b/dnsapi/dns_yandex.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env sh +# Author: non7top@gmail.com +# 07 Jul 2017 +# report bugs at https://github.com/non7top/acme.sh + +# Values to export: +# export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_yandex_add() { + fulldomain="${1}" + txtvalue="${2}" + _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" + _PDD_credentials + export _H1="PddToken: $PDD_Token" + + curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" + curUri="https://pddimp.yandex.ru/api2/admin/dns/add" + curResult="$(_post "${curData}" "${curUri}")" + _debug "Result: $curResult" +} + +#Usage: dns_myapi_rm _acme-challenge.www.domain.com +dns_yandex_rm() { + fulldomain="${1}" + _debug "Calling: dns_yandex_rm() '${fulldomain}'" + _PDD_credentials + export _H1="PddToken: $PDD_Token" + local record_id=$( pdd_get_record_id ${fulldomain} ) + + curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curUri="https://pddimp.yandex.ru/api2/admin/dns/del" + curData="domain=${curDomain}&record_id=${record_id}" + curResult="$(_post "${curData}" "${curUri}")" + _debug "Result: $curResult" +} + +#################### Private functions below ################################## + +_PDD_credentials() { + if [ -z "${PDD_Token}" ]; then + PDD_Token="" + _err "You haven't specified the ISPConfig Login data." + return 1 + else + _saveaccountconf PDD_Token "${PDD_Token}" + fi +} + +pdd_get_record_id() { + local fulldomain="${1}" + local curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + local curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" + local curResult="$(_get "${curUri}")" + echo ${curResult} | \ +python -c ' +import sys, json; +rs=json.load(sys.stdin)["records"] +for r in rs: + if r["fqdn"]=="${fulldomain}": + print r["record_id"] + exit +' +} From 6445a7674bd31e521e1eec12d16def544893dd69 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 21:52:47 +0300 Subject: [PATCH 468/620] fix syntax --- dnsapi/dns_yandex.sh | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index db38eb52..a792d495 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials export _H1="PddToken: $PDD_Token" - curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -30,10 +30,10 @@ dns_yandex_rm() { _debug "Calling: dns_yandex_rm() '${fulldomain}'" _PDD_credentials export _H1="PddToken: $PDD_Token" - local record_id=$( pdd_get_record_id ${fulldomain} ) + record_id=$( pdd_get_record_id ${fulldomain} ) - curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -53,17 +53,17 @@ _PDD_credentials() { } pdd_get_record_id() { - local fulldomain="${1}" - local curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - local curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" - local curResult="$(_get "${curUri}")" + fulldomain="${1}" + curDomain="$(echo "${fulldomain}" |awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" + curResult="$(_get "${curUri}")" echo ${curResult} | \ -python -c ' + python -c " import sys, json; -rs=json.load(sys.stdin)["records"] +rs=json.load(sys.stdin)[\"records\"] for r in rs: - if r["fqdn"]=="${fulldomain}": - print r["record_id"] + if r[\"fqdn\"]==\"${fulldomain}\": + print r[\"record_id\"] exit -' +" } From a2038ab07e485153ac5b73fb5a8991d6c01c2352 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 21:57:27 +0300 Subject: [PATCH 469/620] fix syntax --- dnsapi/dns_yandex.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index a792d495..1b4b9ae3 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" + curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -30,10 +30,10 @@ dns_yandex_rm() { _debug "Calling: dns_yandex_rm() '${fulldomain}'" _PDD_credentials export _H1="PddToken: $PDD_Token" - record_id=$( pdd_get_record_id ${fulldomain} ) + record_id=$( pdd_get_record_id "${fulldomain}" ) - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" + curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -57,8 +57,8 @@ pdd_get_record_id() { curDomain="$(echo "${fulldomain}" |awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}")" - echo ${curResult} | \ - python -c " + echo "${curResult}" \ + | python -c " import sys, json; rs=json.load(sys.stdin)[\"records\"] for r in rs: From bd41f50ba5e7bd55f78fd3658da1470c57a33f0e Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 22:02:34 +0300 Subject: [PATCH 470/620] fix formatting --- dnsapi/dns_yandex.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 1b4b9ae3..077e6614 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials export _H1="PddToken: $PDD_Token" - curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" + curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -30,10 +30,10 @@ dns_yandex_rm() { _debug "Calling: dns_yandex_rm() '${fulldomain}'" _PDD_credentials export _H1="PddToken: $PDD_Token" - record_id=$( pdd_get_record_id "${fulldomain}" ) + record_id=$(pdd_get_record_id "${fulldomain}") - curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" + curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -54,11 +54,11 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain="$(echo "${fulldomain}" |awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}")" echo "${curResult}" \ - | python -c " + | python -c " import sys, json; rs=json.load(sys.stdin)[\"records\"] for r in rs: From 8f3a3b293d46708eef7c6b5018379d721d82e815 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 13:00:42 +0300 Subject: [PATCH 471/620] add newline and checks --- 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 077e6614..fc707816 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -13,7 +13,7 @@ dns_yandex_add() { fulldomain="${1}" txtvalue="${2}" _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" - _PDD_credentials + _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" @@ -28,7 +28,7 @@ dns_yandex_add() { dns_yandex_rm() { fulldomain="${1}" _debug "Calling: dns_yandex_rm() '${fulldomain}'" - _PDD_credentials + _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") @@ -67,3 +67,4 @@ for r in rs: exit " } + From 256cb90f3cf878086fa14b21f0379a11344b8cec Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 13:15:01 +0300 Subject: [PATCH 472/620] remove awk --- dnsapi/dns_yandex.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index fc707816..f6a7248e 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" - curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -32,8 +32,8 @@ dns_yandex_rm() { export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" - curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" From 9ec54ef89b50fd2367706c7d1747ccc9d36c63ca Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 13:21:55 +0300 Subject: [PATCH 473/620] shfmt fixes --- dnsapi/dns_yandex.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index f6a7248e..664da77b 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -32,8 +32,8 @@ dns_yandex_rm() { export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -67,4 +67,3 @@ for r in rs: exit " } - From 266e9d06194c7eea0dd7854fd7c8fa9da680fcce Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 20:00:02 +0300 Subject: [PATCH 474/620] remove python --- dnsapi/dns_yandex.sh | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 664da77b..2a47150c 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -31,6 +31,7 @@ dns_yandex_rm() { _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") + _debug "Result: $record_id" curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" @@ -54,16 +55,10 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" - curResult="$(_get "${curUri}")" - echo "${curResult}" \ - | python -c " -import sys, json; -rs=json.load(sys.stdin)[\"records\"] -for r in rs: - if r[\"fqdn\"]==\"${fulldomain}\": - print r[\"record_id\"] - exit -" + curResult="$(_get "${curUri}" | _normalizeJson)" + _debug "Result: $curResult" + echo "$curResult" | grep -o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' } From 796647158ea23ebf673d817a254e1d61c7ce652c Mon Sep 17 00:00:00 2001 From: Santeri Date: Mon, 10 Jul 2017 15:36:16 +0400 Subject: [PATCH 475/620] Removed double quotes from _opt Broke GoDaddy cpanel causing error (thanks Hedgehog) --- deploy/cpanel.sh | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/deploy/cpanel.sh b/deploy/cpanel.sh index 6ab012a3..b9552397 100644 --- a/deploy/cpanel.sh +++ b/deploy/cpanel.sh @@ -1,12 +1,12 @@ -#!/bin/bash +#!/usr/bin/env sh # Here is the script to deploy the cert to your cpanel using the cpanel API. -# Uses command line uapi. Cpanel username is needed only when run as root. -# Returns 0 when success, otherwise error. +# Uses command line uapi. +# Cpanel username is needed only when run as root (I did not test this). +# Returns 0 when success. # Written by Santeri Kannisto # Public domain, 2017 #export DEPLOY_CPANEL_USER=myusername -#export DEPLOY_CPANEL_PASSWORD=PASSWORD ######## Public functions ##################### @@ -26,32 +26,28 @@ cpanel_deploy() { _debug _cfullchain "$_cfullchain" # read cert and key files and urlencode both - _certstr=`cat "$_ccert"` - _keystr=`cat "$_ckey"` + _certstr=$(cat "$_ccert") + _keystr=$(cat "$_ckey") _cert=$(php -r "echo urlencode(\"$_certstr\");") _key=$(php -r "echo urlencode(\"$_keystr\");") _debug _cert "$_cert" _debug _key "$_key" - if [[ $EUID -eq 0 ]] - then - _opt="--user=$DEPLOY_CPANEL_USER SSL install_ssl" - else - _opt="SSL install_ssl" - fi - - _debug _opt "$_opt" + if [ "$(id -u)" = 0 ]; then + _opt="--user=$DEPLOY_CPANEL_USER" + _debug _opt "$_opt" + fi - response=$(uapi $_opt domain="$_cdommain" cert="$_cert" key="$_key") + _response=$(uapi $_opt SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") - if [ $? -ne 0 ] - then + if [ $? -ne 0 ]; then _err "Error in deploying certificate:" - _err "$response" + _err "$_response" return 1 fi - _debug response "$response" + _debug response "$_response" _info "Certificate successfully deployed" + return 0 } From c4d0aec536dcd8886579d7f528f85217304c7366 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 10 Jul 2017 19:51:55 +0800 Subject: [PATCH 476/620] do not retry for a invalid cert in cronjob. fix https://github.com/Neilpang/acme.sh/issues/939 --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index 35842f4e..486f8678 100755 --- a/acme.sh +++ b/acme.sh @@ -4033,6 +4033,11 @@ renew() { return "$RENEW_SKIP" fi + if [ "$IN_CRON" = "1" ] && [ -z "$Le_CertCreateTime" ]; then + _info "Skip invalid cert for: $Le_Domain" + return 0 + fi + IS_RENEW="1" 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" res="$?" From a577c7215f0b2a5ad6729b175fb6e0033abeb4d5 Mon Sep 17 00:00:00 2001 From: Santeri Date: Mon, 10 Jul 2017 16:43:42 +0400 Subject: [PATCH 477/620] One more change to pass the check shellcheck test Now it is tested and works also when run as a root. --- deploy/cpanel.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/deploy/cpanel.sh b/deploy/cpanel.sh index b9552397..9de8dbbb 100644 --- a/deploy/cpanel.sh +++ b/deploy/cpanel.sh @@ -1,7 +1,6 @@ #!/usr/bin/env sh # Here is the script to deploy the cert to your cpanel using the cpanel API. -# Uses command line uapi. -# Cpanel username is needed only when run as root (I did not test this). +# Uses command line uapi. --user option is needed only if run as root. # Returns 0 when success. # Written by Santeri Kannisto # Public domain, 2017 @@ -35,12 +34,11 @@ cpanel_deploy() { _debug _key "$_key" if [ "$(id -u)" = 0 ]; then - _opt="--user=$DEPLOY_CPANEL_USER" - _debug _opt "$_opt" + _response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") + else + _response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") fi - _response=$(uapi $_opt SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") - if [ $? -ne 0 ]; then _err "Error in deploying certificate:" _err "$_response" From 10cb7585a7140c7f709e2dcdee27913a55503545 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Tue, 11 Jul 2017 02:19:39 +0300 Subject: [PATCH 478/620] fix egrep and exit --- dnsapi/dns_yandex.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 2a47150c..d2ccf18e 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -13,7 +13,7 @@ dns_yandex_add() { fulldomain="${1}" txtvalue="${2}" _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" - _PDD_credentials || exit 1 + _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" @@ -28,7 +28,7 @@ dns_yandex_add() { dns_yandex_rm() { fulldomain="${1}" _debug "Calling: dns_yandex_rm() '${fulldomain}'" - _PDD_credentials || exit 1 + _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" @@ -60,5 +60,5 @@ pdd_get_record_id() { curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}" | _normalizeJson)" _debug "Result: $curResult" - echo "$curResult" | grep -o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' + echo "$curResult" | _egrep_o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' } From e6a95ecd0889779a39e988b392dcdd9568f34798 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Wed, 12 Jul 2017 03:51:48 +0300 Subject: [PATCH 479/620] rework root domain detection --- dnsapi/dns_yandex.sh | 57 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index d2ccf18e..4b00219b 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,9 @@ dns_yandex_add() { _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" + curDomain=$(_PDD_get_domain $fulldomain) + _debug "Found suitable domain in pdd: $curDomain" + curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -33,8 +34,10 @@ dns_yandex_rm() { record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" + curDomain=$(_PDD_get_domain $fulldomain) + _debug "Found suitable domain in pdd: $curDomain" + curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" + curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -43,10 +46,47 @@ dns_yandex_rm() { #################### Private functions below ################################## +_PDD_get_domain() { + fulldomain="${1}" + __page=1 + __last=0 + while [ $__last -eq 0 ]; do + uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20" + res1=$(_get $uri1 | _normalizeJson) + #_debug "$res1" + __found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p') + _debug "found: $__found results on page" + if [ $__found -lt 20 ]; then + _debug "last page: $__page" + __last=1 + fi + + __all_domains="$__all_domains $(echo "$res1" | sed -e "s@,@\n@g" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')" + + __page=$(_math $__page + 1) + done + + k=2 + while [ $k -lt 10 ]; do + __t=$(echo "$fulldomain" | cut -d . -f $k-100) + _debug "finding zone for domain $__t" + for d in $__all_domains; do + if [ "$d" == "$__t" ]; then + echo "$__t" + return + fi + done + k=$(_math $k + 1) + done + _err "No suitable domain found in your account" + return 1 +} + _PDD_credentials() { if [ -z "${PDD_Token}" ]; then PDD_Token="" - _err "You haven't specified the ISPConfig Login data." + _err "You need to export PDD_Token=xxxxxxxxxxxxxxxxx" + _err "You can get it at https://pddimp.yandex.ru/api2/admin/get_token" return 1 else _saveaccountconf PDD_Token "${PDD_Token}" @@ -55,8 +95,11 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" + + curDomain=$(_PDD_get_domain $fulldomain) + _debug "Found suitable domain in pdd: $curDomain" + curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" + curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}" | _normalizeJson)" _debug "Result: $curResult" From 6a9b4db448775b59913563aaeb3280296a0febc3 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Wed, 12 Jul 2017 04:07:18 +0300 Subject: [PATCH 480/620] fix formatting --- dnsapi/dns_yandex.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 4b00219b..eb60d5af 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" - curDomain=$(_PDD_get_domain $fulldomain) + curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" @@ -34,7 +34,7 @@ dns_yandex_rm() { record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" - curDomain=$(_PDD_get_domain $fulldomain) + curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" @@ -52,11 +52,11 @@ _PDD_get_domain() { __last=0 while [ $__last -eq 0 ]; do uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20" - res1=$(_get $uri1 | _normalizeJson) + res1=$(_get "$uri1" | _normalizeJson) #_debug "$res1" __found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p') _debug "found: $__found results on page" - if [ $__found -lt 20 ]; then + if [ "$__found" -lt 20 ]; then _debug "last page: $__page" __last=1 fi @@ -71,7 +71,7 @@ _PDD_get_domain() { __t=$(echo "$fulldomain" | cut -d . -f $k-100) _debug "finding zone for domain $__t" for d in $__all_domains; do - if [ "$d" == "$__t" ]; then + if [ "$d" = "$__t" ]; then echo "$__t" return fi @@ -96,7 +96,7 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain=$(_PDD_get_domain $fulldomain) + curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" From 7d64e141e45be32479773f8a4fb44bd8304dacc1 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Wed, 12 Jul 2017 20:24:54 +0200 Subject: [PATCH 481/620] Add dns_he - DNS API script for Hurricane Electric DNS service ... Although not yet fully Posix compatible. --- dnsapi/README.md | 18 +++++ dnsapi/dns_he.sh | 200 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+) create mode 100755 dnsapi/dns_he.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index 41f89a88..15399048 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -572,6 +572,24 @@ 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 Hurricane Electric + +Hurricane Electric doesn't have an API so just set your login credentials like so: + +``` +export HE_Username="yourusername" +export HE_Password="password" +``` + +Then you can issue your certificate: + +``` +acme.sh --issue --dns dns_he -d example.com -d www.example.com +``` + +The `HE_Username` and `HE_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +Please report any issues to https://github.com/angel333/acme.sh or to . # Use custom API diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh new file mode 100755 index 00000000..269db8d2 --- /dev/null +++ b/dnsapi/dns_he.sh @@ -0,0 +1,200 @@ +#!/usr/bin/env sh + +# TODO Somehow use _get instead of curl - not sure how to support +# cookies though... + +######################################################################## +# Hurricane Electric hook script for acme.sh +# +# Environment variables: +# +# - $HE_Username (your dns.he.net username) +# - $HE_Password (your dns.he.net password) +# +# Author: Ondrej Simek +# Git repo: https://github.com/angel333/acme.sh + + +#-- dns_he_add() - Add TXT record -------------------------------------- +# Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..." + +dns_he_add() { + _full_domain=$1 + _txt_value=$2 + _info "Using DNS-01 Hurricane Electric hook" + + _authenticate || return 1 + _saveaccountconf HE_Username "$HE_Username" + _saveaccountconf HE_Password "$HE_Password" + + # fills in the $_zone_id + _find_zone $_full_domain || return 1 + _debug "Zone id \"$_zone_id\" will be used." + + curl -L --silent --show-error --cookie "$_he_cookie" \ + --form "account=" \ + --form "menu=edit_zone" \ + --form "Type=TXT" \ + --form "hosted_dns_zoneid=$_zone_id" \ + --form "hosted_dns_recordid=" \ + --form "hosted_dns_editzone=1" \ + --form "Priority=" \ + --form "Name=$_full_domain" \ + --form "Content=$_txt_value" \ + --form "TTL=300" \ + --form "hosted_dns_editrecord=Submit" \ + "https://dns.he.net/" \ + > /dev/null +} + + +#-- dns_he_rm() - Remove TXT record ------------------------------------ +# Usage: dns_he_rm _acme-challenge.subdomain.domain.com "XyZ123..." + +dns_he_rm() { + _full_domain=$1 + _txt_value=$2 + _info "Cleaning up after DNS-01 Hurricane Electric hook" + + _authenticate || return 1 + + # fills in the $_zone_id + _find_zone $_full_domain || return 1 + _debug "Zone id \"$_zone_id\" will be used." + + # Find the record id to clean + _record_id=$( \ + curl -L --silent --show-error --cookie "$_he_cookie" \ + "https://dns.he.net/?hosted_dns_zoneid=$_zone_id&menu=edit_zone&hosted_dns_editzone" \ + | grep -A 1 "data=\"\("\)\?${_txt_value}\("\)\?\"" \ + | tail -n 1 \ + | _egrep_o "'[[:digit:]]+','[^']+','TXT'" \ + | cut -b 2- \ + | _egrep_o "[[:digit:]]+" \ + | head -n1) # ... oh my, what have I done... + + # Remove the record + curl -L --silent --show-error --cookie "$_he_cookie" \ + --form "menu=edit_zone" \ + --form "hosted_dns_zoneid=$_zone_id" \ + --form "hosted_dns_recordid=$_record_id" \ + --form "hosted_dns_editzone=1" \ + --form "hosted_dns_delrecord=1" \ + --form "hosted_dns_delconfirm=delete" \ + --form "hosted_dns_editzone=1" \ + "https://dns.he.net/" \ + | grep '
Successfully removed record.
' \ + > /dev/null + if [ $? -eq 0 ]; then + _info "Record removed successfuly." + else + _err \ + "Could not clean (remove) up the record. Please go to HE" \ + "administration interface and clean it by hand." + fi +} + + +########################## PRIVATE FUNCTIONS ########################### + + +#-- _find_zone() ------------------------------------------------------- + +# Usage: _authenticate +# +# - needs $HE_Username and $HE_Password +# - sets the $_he_cookie + +_authenticate() { + if [ -z "$HE_Username" ] && [ -z "$HE_Password" ]; then + _err \ + 'No auth details provided. Please set user credentials using the \ + \$HE_Username and \$HE_Password envoronment variables.' + return 1 + fi + # Just get a session + _he_cookie=$( \ + curl -L --silent --show-error -I "https://dns.he.net/" \ + | grep '^Set-Cookie:' \ + | _egrep_o 'CGISESSID=[a-z0-9]*') + # Attempt login + curl -L --silent --show-error --cookie "$_he_cookie" \ + --form "email=${HE_Username}" \ + --form "pass=${HE_Password}" \ + "https://dns.he.net/" \ + > /dev/null + # TODO detect unsuccessful logins +} + + +#-- _find_zone() ------------------------------------------------------- + +# Returns the most specific zone found in administration interface. +# +# - needs $_he_cookie +# +# Example: +# +# _find_zone first.second.third.co.uk +# +# ... will return the first zone that exists in admin out of these: +# - "first.second.third.co.uk" +# - "second.third.co.uk" +# - "third.co.uk" +# - "co.uk" <-- unlikely +# - "uk" <-' +# +# (another approach would be something like this: +# https://github.com/hlandau/acme/blob/master/_doc/dns.hook +# - that's better if there are multiple pages. It's so much simpler. +# ) + +_find_zone() { + + _domain="$1" + + ## _all_zones is an array that looks like this: + ## ( zone1:id zone2:id ... ) + _all_zones=( $(curl -L --silent --show-error --cookie "$_he_cookie" \ + "https://dns.he.net/" \ + | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" \ + | cut -d '"' -f 3,5 --output-delimiter=":" \ + ) ) + + _strip_counter=1 + while [ true ] + do + _attempted_zone=$(echo $_domain | cut -d . -f ${_strip_counter}-) + + # All possible zone names have been tried + if [ "$_attempted_zone" == "" ] + then + _err "No zone for domain \"$_domain\" found." + break + fi + + # Walk through all zones on the account + #echo "$_all_zones" | while IFS=' ' read _zone_name _zone_id + for i in ${_all_zones[@]} + do + _zone_name=$(echo $i | cut -d ':' -f 1) + _zone_id=$(echo $i | cut -d ':' -f 2) + if [ "$_zone_name" == "$_attempted_zone" ] + then + # Zone found - we got $_zone_name and $_zone_id, let's get out... + _debug "Found relevant zone \"$_zone_name\" with id" \ + "\"$_zone_id\" - will be used for domain \"$_domain\"." + return 0 + fi + done + + _debug "Zone \"$_attempted_zone\" doesn't exist, let's try another \ + variation." + _strip_counter=$(expr $_strip_counter + 1) + done + + # No zone found. + return 1 +} + +# vim: et:ts=2:sw=2: From accbda9d2f91c48c31f5e10ec073c44054647919 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 13 Jul 2017 20:52:44 +0800 Subject: [PATCH 482/620] output log --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 5849eb46..7ca042ea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ ADD ./ /install_acme.sh/ RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/ -RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh +RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | sed 's#> /dev/null##' | crontab - RUN for verb in help \ version \ From 84a251c8c7eea52e819445c4d407fefc2b52c852 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Thu, 13 Jul 2017 17:05:57 +0300 Subject: [PATCH 483/620] add documentation --- README.md | 1 + dnsapi/README.md | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/README.md b/README.md index 7780b9ab..afb8a761 100644 --- a/README.md +++ b/README.md @@ -335,6 +335,7 @@ You don't have to do anything manually! 1. DNSimple API 1. NS1.com API 1. DuckDNS.org API +1. Yandex PDD API (https://pdd.yandex.ru) 1. Name.com API diff --git a/dnsapi/README.md b/dnsapi/README.md index 57c360b7..55fd65a2 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -522,6 +522,21 @@ account file will always store the lastly used domain name. For issues, please report to https://github.com/raidenii/acme.sh/issues. + +## 27. 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. + + ## 28. Use Name.com API You'll need to fill out the form at https://www.name.com/reseller/apply to apply From bdee66fe2942affb0ba0675785d6c0ef567fbf8e Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Thu, 13 Jul 2017 18:37:13 +0300 Subject: [PATCH 484/620] minor fixes --- dnsapi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 55fd65a2..71154033 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -523,7 +523,7 @@ account file will always store the lastly used domain name. For issues, please report to https://github.com/raidenii/acme.sh/issues. -## 27. Use pdd.yandex.ru API +## 28. Use pdd.yandex.ru API ``` export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" @@ -537,7 +537,7 @@ acme.sh --issue --dns dns_yandex -d mydomain.example.org For issues, please report to https://github.com/non7top/acme.sh/issues. -## 28. Use Name.com API +## 29. Use Name.com API You'll need to fill out the form at https://www.name.com/reseller/apply to apply for API username and token. From a460ac021fadffda93359b9acab6508cafcd6c24 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 21:35:22 +0300 Subject: [PATCH 485/620] add pdd.yandex.ru dns api --- dnsapi/dns_yandex.sh | 69 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100755 dnsapi/dns_yandex.sh diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh new file mode 100755 index 00000000..db38eb52 --- /dev/null +++ b/dnsapi/dns_yandex.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env sh +# Author: non7top@gmail.com +# 07 Jul 2017 +# report bugs at https://github.com/non7top/acme.sh + +# Values to export: +# export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_yandex_add() { + fulldomain="${1}" + txtvalue="${2}" + _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" + _PDD_credentials + export _H1="PddToken: $PDD_Token" + + curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" + curUri="https://pddimp.yandex.ru/api2/admin/dns/add" + curResult="$(_post "${curData}" "${curUri}")" + _debug "Result: $curResult" +} + +#Usage: dns_myapi_rm _acme-challenge.www.domain.com +dns_yandex_rm() { + fulldomain="${1}" + _debug "Calling: dns_yandex_rm() '${fulldomain}'" + _PDD_credentials + export _H1="PddToken: $PDD_Token" + local record_id=$( pdd_get_record_id ${fulldomain} ) + + curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curUri="https://pddimp.yandex.ru/api2/admin/dns/del" + curData="domain=${curDomain}&record_id=${record_id}" + curResult="$(_post "${curData}" "${curUri}")" + _debug "Result: $curResult" +} + +#################### Private functions below ################################## + +_PDD_credentials() { + if [ -z "${PDD_Token}" ]; then + PDD_Token="" + _err "You haven't specified the ISPConfig Login data." + return 1 + else + _saveaccountconf PDD_Token "${PDD_Token}" + fi +} + +pdd_get_record_id() { + local fulldomain="${1}" + local curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + local curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" + local curResult="$(_get "${curUri}")" + echo ${curResult} | \ +python -c ' +import sys, json; +rs=json.load(sys.stdin)["records"] +for r in rs: + if r["fqdn"]=="${fulldomain}": + print r["record_id"] + exit +' +} From a09b2c0074f43e017966cb22018100774df76832 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 21:52:47 +0300 Subject: [PATCH 486/620] fix syntax --- dnsapi/dns_yandex.sh | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index db38eb52..a792d495 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials export _H1="PddToken: $PDD_Token" - curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -30,10 +30,10 @@ dns_yandex_rm() { _debug "Calling: dns_yandex_rm() '${fulldomain}'" _PDD_credentials export _H1="PddToken: $PDD_Token" - local record_id=$( pdd_get_record_id ${fulldomain} ) + record_id=$( pdd_get_record_id ${fulldomain} ) - curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo ${fulldomain} | sed -e 's#$curDomain##')" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -53,17 +53,17 @@ _PDD_credentials() { } pdd_get_record_id() { - local fulldomain="${1}" - local curDomain="$(echo ${fulldomain}|awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - local curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" - local curResult="$(_get "${curUri}")" + fulldomain="${1}" + curDomain="$(echo "${fulldomain}" |awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" + curResult="$(_get "${curUri}")" echo ${curResult} | \ -python -c ' + python -c " import sys, json; -rs=json.load(sys.stdin)["records"] +rs=json.load(sys.stdin)[\"records\"] for r in rs: - if r["fqdn"]=="${fulldomain}": - print r["record_id"] + if r[\"fqdn\"]==\"${fulldomain}\": + print r[\"record_id\"] exit -' +" } From e9d540779257ac5378ea594391de387393a03c84 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 21:57:27 +0300 Subject: [PATCH 487/620] fix syntax --- dnsapi/dns_yandex.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index a792d495..1b4b9ae3 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" + curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -30,10 +30,10 @@ dns_yandex_rm() { _debug "Calling: dns_yandex_rm() '${fulldomain}'" _PDD_credentials export _H1="PddToken: $PDD_Token" - record_id=$( pdd_get_record_id ${fulldomain} ) + record_id=$( pdd_get_record_id "${fulldomain}" ) - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$(echo "${fulldomain}" | sed -e 's#$curDomain##')" + curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -57,8 +57,8 @@ pdd_get_record_id() { curDomain="$(echo "${fulldomain}" |awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}")" - echo ${curResult} | \ - python -c " + echo "${curResult}" \ + | python -c " import sys, json; rs=json.load(sys.stdin)[\"records\"] for r in rs: From 18cb11dcbf932fe324c9d0426546e63770cf7355 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sat, 8 Jul 2017 22:02:34 +0300 Subject: [PATCH 488/620] fix formatting --- dnsapi/dns_yandex.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 1b4b9ae3..077e6614 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials export _H1="PddToken: $PDD_Token" - curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" + curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -30,10 +30,10 @@ dns_yandex_rm() { _debug "Calling: dns_yandex_rm() '${fulldomain}'" _PDD_credentials export _H1="PddToken: $PDD_Token" - record_id=$( pdd_get_record_id "${fulldomain}" ) + record_id=$(pdd_get_record_id "${fulldomain}") - curDomain="$( echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" - curSubdomain="$( echo "${fulldomain}" | sed -e "s#$curDomain##" )" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" + curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -54,11 +54,11 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain="$(echo "${fulldomain}" |awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}' )" + curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}")" echo "${curResult}" \ - | python -c " + | python -c " import sys, json; rs=json.load(sys.stdin)[\"records\"] for r in rs: From 42ab7a5d725109a15df5d0a049232a3f461908bc Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 13:00:42 +0300 Subject: [PATCH 489/620] add newline and checks --- 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 077e6614..fc707816 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -13,7 +13,7 @@ dns_yandex_add() { fulldomain="${1}" txtvalue="${2}" _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" - _PDD_credentials + _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" @@ -28,7 +28,7 @@ dns_yandex_add() { dns_yandex_rm() { fulldomain="${1}" _debug "Calling: dns_yandex_rm() '${fulldomain}'" - _PDD_credentials + _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") @@ -67,3 +67,4 @@ for r in rs: exit " } + From d61b687853e00f72dbfc1d7137767ba0ae4fdf57 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 13:15:01 +0300 Subject: [PATCH 490/620] remove awk --- dnsapi/dns_yandex.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index fc707816..f6a7248e 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" - curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -32,8 +32,8 @@ dns_yandex_rm() { export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" - curSubdomain="$(echo "${fulldomain}" | sed -e "s#$curDomain##")" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" From 57d1db58db275bda6e89608d5af75ae4f60320f7 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 13:21:55 +0300 Subject: [PATCH 491/620] shfmt fixes --- dnsapi/dns_yandex.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index f6a7248e..664da77b 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,8 @@ dns_yandex_add() { _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -32,8 +32,8 @@ dns_yandex_rm() { export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev )" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev )" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -67,4 +67,3 @@ for r in rs: exit " } - From a0df46258dfb327ff5f2de471b13d1250b4ea3e3 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Sun, 9 Jul 2017 20:00:02 +0300 Subject: [PATCH 492/620] remove python --- dnsapi/dns_yandex.sh | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 664da77b..2a47150c 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -31,6 +31,7 @@ dns_yandex_rm() { _PDD_credentials || exit 1 export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") + _debug "Result: $record_id" curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" @@ -54,16 +55,10 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain="$(echo "${fulldomain}" | awk -F. '{printf("%s.%s\n",$(NF-1), $NF)}')" + curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" + curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" - curResult="$(_get "${curUri}")" - echo "${curResult}" \ - | python -c " -import sys, json; -rs=json.load(sys.stdin)[\"records\"] -for r in rs: - if r[\"fqdn\"]==\"${fulldomain}\": - print r[\"record_id\"] - exit -" + curResult="$(_get "${curUri}" | _normalizeJson)" + _debug "Result: $curResult" + echo "$curResult" | grep -o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' } From fceb728501472961e73ed8bbdd292311de31cd40 Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Tue, 11 Jul 2017 02:19:39 +0300 Subject: [PATCH 493/620] fix egrep and exit --- dnsapi/dns_yandex.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 2a47150c..d2ccf18e 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -13,7 +13,7 @@ dns_yandex_add() { fulldomain="${1}" txtvalue="${2}" _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" - _PDD_credentials || exit 1 + _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" @@ -28,7 +28,7 @@ dns_yandex_add() { dns_yandex_rm() { fulldomain="${1}" _debug "Calling: dns_yandex_rm() '${fulldomain}'" - _PDD_credentials || exit 1 + _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" @@ -60,5 +60,5 @@ pdd_get_record_id() { curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}" | _normalizeJson)" _debug "Result: $curResult" - echo "$curResult" | grep -o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' + echo "$curResult" | _egrep_o "{[^{]*\"content\":[^{]*\"subdomain\":\"${curSubdomain}\"" | sed -n -e 's#.* "record_id": \(.*\),[^,]*#\1#p' } From eb6be88fac9510aa137b3dea9e16b56aa3d10c1e Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Wed, 12 Jul 2017 03:51:48 +0300 Subject: [PATCH 494/620] rework root domain detection --- dnsapi/dns_yandex.sh | 57 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index d2ccf18e..4b00219b 100755 --- a/dnsapi/dns_yandex.sh +++ b/dnsapi/dns_yandex.sh @@ -16,8 +16,9 @@ dns_yandex_add() { _PDD_credentials || return 1 export _H1="PddToken: $PDD_Token" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" + curDomain=$(_PDD_get_domain $fulldomain) + _debug "Found suitable domain in pdd: $curDomain" + curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" curUri="https://pddimp.yandex.ru/api2/admin/dns/add" curResult="$(_post "${curData}" "${curUri}")" @@ -33,8 +34,10 @@ dns_yandex_rm() { record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" + curDomain=$(_PDD_get_domain $fulldomain) + _debug "Found suitable domain in pdd: $curDomain" + curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" + curUri="https://pddimp.yandex.ru/api2/admin/dns/del" curData="domain=${curDomain}&record_id=${record_id}" curResult="$(_post "${curData}" "${curUri}")" @@ -43,10 +46,47 @@ dns_yandex_rm() { #################### Private functions below ################################## +_PDD_get_domain() { + fulldomain="${1}" + __page=1 + __last=0 + while [ $__last -eq 0 ]; do + uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20" + res1=$(_get $uri1 | _normalizeJson) + #_debug "$res1" + __found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p') + _debug "found: $__found results on page" + if [ $__found -lt 20 ]; then + _debug "last page: $__page" + __last=1 + fi + + __all_domains="$__all_domains $(echo "$res1" | sed -e "s@,@\n@g" | grep '"name"' | cut -d: -f2 | sed -e 's@"@@g')" + + __page=$(_math $__page + 1) + done + + k=2 + while [ $k -lt 10 ]; do + __t=$(echo "$fulldomain" | cut -d . -f $k-100) + _debug "finding zone for domain $__t" + for d in $__all_domains; do + if [ "$d" == "$__t" ]; then + echo "$__t" + return + fi + done + k=$(_math $k + 1) + done + _err "No suitable domain found in your account" + return 1 +} + _PDD_credentials() { if [ -z "${PDD_Token}" ]; then PDD_Token="" - _err "You haven't specified the ISPConfig Login data." + _err "You need to export PDD_Token=xxxxxxxxxxxxxxxxx" + _err "You can get it at https://pddimp.yandex.ru/api2/admin/get_token" return 1 else _saveaccountconf PDD_Token "${PDD_Token}" @@ -55,8 +95,11 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain="$(echo "${fulldomain}" | rev | cut -d . -f 1-2 | rev)" - curSubdomain="$(echo "${fulldomain}" | rev | cut -d . -f 3- | rev)" + + curDomain=$(_PDD_get_domain $fulldomain) + _debug "Found suitable domain in pdd: $curDomain" + curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" + curUri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${curDomain}" curResult="$(_get "${curUri}" | _normalizeJson)" _debug "Result: $curResult" From c848d3ee22b085a18ff52567efb7d0f213374f7b Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Wed, 12 Jul 2017 04:07:18 +0300 Subject: [PATCH 495/620] fix formatting --- dnsapi/dns_yandex.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_yandex.sh b/dnsapi/dns_yandex.sh index 4b00219b..eb60d5af 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" - curDomain=$(_PDD_get_domain $fulldomain) + curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" curData="domain=${curDomain}&type=TXT&subdomain=${curSubdomain}&ttl=360&content=${txtvalue}" @@ -34,7 +34,7 @@ dns_yandex_rm() { record_id=$(pdd_get_record_id "${fulldomain}") _debug "Result: $record_id" - curDomain=$(_PDD_get_domain $fulldomain) + curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" @@ -52,11 +52,11 @@ _PDD_get_domain() { __last=0 while [ $__last -eq 0 ]; do uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20" - res1=$(_get $uri1 | _normalizeJson) + res1=$(_get "$uri1" | _normalizeJson) #_debug "$res1" __found=$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p') _debug "found: $__found results on page" - if [ $__found -lt 20 ]; then + if [ "$__found" -lt 20 ]; then _debug "last page: $__page" __last=1 fi @@ -71,7 +71,7 @@ _PDD_get_domain() { __t=$(echo "$fulldomain" | cut -d . -f $k-100) _debug "finding zone for domain $__t" for d in $__all_domains; do - if [ "$d" == "$__t" ]; then + if [ "$d" = "$__t" ]; then echo "$__t" return fi @@ -96,7 +96,7 @@ _PDD_credentials() { pdd_get_record_id() { fulldomain="${1}" - curDomain=$(_PDD_get_domain $fulldomain) + curDomain=$(_PDD_get_domain "$fulldomain") _debug "Found suitable domain in pdd: $curDomain" curSubdomain="$(echo "${fulldomain}" | sed -e "s@.${curDomain}\$@@")" From 377fe5ecdeb750a95ffdb38b669d66d77ad0a03d Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Thu, 13 Jul 2017 17:05:57 +0300 Subject: [PATCH 496/620] add documentation --- README.md | 1 + dnsapi/README.md | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/README.md b/README.md index 5c306a59..ae73b0fe 100644 --- a/README.md +++ b/README.md @@ -335,6 +335,7 @@ You don't have to do anything manually! 1. DNSimple API 1. NS1.com API 1. DuckDNS.org API +1. Yandex PDD API (https://pdd.yandex.ru) 1. Name.com API 1. Dyn Managed DNS API diff --git a/dnsapi/README.md b/dnsapi/README.md index 41f89a88..afaf94f8 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -522,6 +522,21 @@ account file will always store the lastly used domain name. For issues, please report to https://github.com/raidenii/acme.sh/issues. + +## 27. 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. + + ## 28. Use Name.com API You'll need to fill out the form at https://www.name.com/reseller/apply to apply From 283ef9adb7a9f5f33e04ce03b6db158802a30f3a Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Thu, 13 Jul 2017 18:37:13 +0300 Subject: [PATCH 497/620] minor fixes --- dnsapi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index afaf94f8..3d571af1 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -523,7 +523,7 @@ account file will always store the lastly used domain name. For issues, please report to https://github.com/raidenii/acme.sh/issues. -## 27. Use pdd.yandex.ru API +## 28. Use pdd.yandex.ru API ``` export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" @@ -537,7 +537,7 @@ acme.sh --issue --dns dns_yandex -d mydomain.example.org For issues, please report to https://github.com/non7top/acme.sh/issues. -## 28. Use Name.com API +## 29. Use Name.com API You'll need to fill out the form at https://www.name.com/reseller/apply to apply for API username and token. From ae302ee600b1a07bd1132676ab204df72208e15b Mon Sep 17 00:00:00 2001 From: Vladimir Berezhnoy Date: Fri, 14 Jul 2017 03:51:08 +0300 Subject: [PATCH 498/620] reformat docs --- README.md | 2 +- dnsapi/README.md | 29 +++++++++++++---------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index ae73b0fe..5a3a3adf 100644 --- a/README.md +++ b/README.md @@ -335,9 +335,9 @@ You don't have to do anything manually! 1. DNSimple API 1. NS1.com API 1. DuckDNS.org API -1. Yandex PDD API (https://pdd.yandex.ru) 1. Name.com API 1. Dyn Managed DNS API +1. Yandex PDD API (https://pdd.yandex.ru) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 3d571af1..d3dff12a 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -522,22 +522,7 @@ account file will always store the lastly used domain name. For issues, please report to https://github.com/raidenii/acme.sh/issues. - -## 28. 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. - - -## 29. Use Name.com API +## 28. Use Name.com API You'll need to fill out the form at https://www.name.com/reseller/apply to apply for API username and token. @@ -587,6 +572,18 @@ 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. # Use custom API From 90fd18bf423b91e6c48aa38ed1fa6dba52cde5e7 Mon Sep 17 00:00:00 2001 From: Santeri Date: Tue, 18 Jul 2017 15:48:17 +0400 Subject: [PATCH 499/620] Renamed script to cpanel_uapi.sh As per Neil's request. --- deploy/{cpanel.sh => cpanel_uapi.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename deploy/{cpanel.sh => cpanel_uapi.sh} (100%) diff --git a/deploy/cpanel.sh b/deploy/cpanel_uapi.sh similarity index 100% rename from deploy/cpanel.sh rename to deploy/cpanel_uapi.sh From d09b5cb80eab19fb5e14a484cca5de09fb5c01ef Mon Sep 17 00:00:00 2001 From: Santeri Date: Wed, 19 Jul 2017 07:39:21 +0400 Subject: [PATCH 500/620] Rename cpanel_uapi.sh to cpanel_deploy.sh --- deploy/{cpanel_uapi.sh => cpanel_deploy.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename deploy/{cpanel_uapi.sh => cpanel_deploy.sh} (100%) diff --git a/deploy/cpanel_uapi.sh b/deploy/cpanel_deploy.sh similarity index 100% rename from deploy/cpanel_uapi.sh rename to deploy/cpanel_deploy.sh From 4286b2917ef97ab44d0fd6208d183979633a401a Mon Sep 17 00:00:00 2001 From: Santeri Date: Wed, 19 Jul 2017 12:22:00 +0400 Subject: [PATCH 501/620] renamed function --- deploy/{cpanel_deploy.sh => cpanel_uapi.sh} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename deploy/{cpanel_deploy.sh => cpanel_uapi.sh} (98%) diff --git a/deploy/cpanel_deploy.sh b/deploy/cpanel_uapi.sh similarity index 98% rename from deploy/cpanel_deploy.sh rename to deploy/cpanel_uapi.sh index 9de8dbbb..ded50d0c 100644 --- a/deploy/cpanel_deploy.sh +++ b/deploy/cpanel_uapi.sh @@ -11,7 +11,7 @@ #domain keyfile certfile cafile fullchain -cpanel_deploy() { +cpanel_uapi() { _cdomain="$1" _ckey="$2" _ccert="$3" From 4285d81ca9d2805e99cf4ed0b601891b4ffd77ce Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sun, 23 Jul 2017 05:00:02 +0200 Subject: [PATCH 502/620] Get rid of curl. --- dnsapi/dns_he.sh | 102 +++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 65 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 269db8d2..141268ac 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -1,8 +1,5 @@ #!/usr/bin/env sh -# TODO Somehow use _get instead of curl - not sure how to support -# cookies though... - ######################################################################## # Hurricane Electric hook script for acme.sh # @@ -23,7 +20,12 @@ dns_he_add() { _txt_value=$2 _info "Using DNS-01 Hurricane Electric hook" - _authenticate || return 1 + if [ -z "$HE_Username" ] && [ -z "$HE_Password" ]; then + _err \ + 'No auth details provided. Please set user credentials using the \ + \$HE_Username and \$HE_Password envoronment variables.' + return 1 + fi _saveaccountconf HE_Username "$HE_Username" _saveaccountconf HE_Password "$HE_Password" @@ -31,20 +33,20 @@ dns_he_add() { _find_zone $_full_domain || return 1 _debug "Zone id \"$_zone_id\" will be used." - curl -L --silent --show-error --cookie "$_he_cookie" \ - --form "account=" \ - --form "menu=edit_zone" \ - --form "Type=TXT" \ - --form "hosted_dns_zoneid=$_zone_id" \ - --form "hosted_dns_recordid=" \ - --form "hosted_dns_editzone=1" \ - --form "Priority=" \ - --form "Name=$_full_domain" \ - --form "Content=$_txt_value" \ - --form "TTL=300" \ - --form "hosted_dns_editrecord=Submit" \ - "https://dns.he.net/" \ - > /dev/null + body="email=${HE_Username}&pass=${HE_Password}" + body="$body&account=" + body="$body&account=" + body="$body&menu=edit_zone" + body="$body&Type=TXT" + body="$body&hosted_dns_zoneid=$_zone_id" + body="$body&hosted_dns_recordid=" + body="$body&hosted_dns_editzone=1" + body="$body&Priority=" + body="$body&Name=$_full_domain" + body="$body&Content=$_txt_value" + body="$body&TTL=300" + body="$body&hosted_dns_editrecord=Submit" + _post $body "https://dns.he.net/" >/dev/null } @@ -56,16 +58,16 @@ dns_he_rm() { _txt_value=$2 _info "Cleaning up after DNS-01 Hurricane Electric hook" - _authenticate || return 1 - # fills in the $_zone_id _find_zone $_full_domain || return 1 _debug "Zone id \"$_zone_id\" will be used." # Find the record id to clean - _record_id=$( \ - curl -L --silent --show-error --cookie "$_he_cookie" \ - "https://dns.he.net/?hosted_dns_zoneid=$_zone_id&menu=edit_zone&hosted_dns_editzone" \ + body="email=${HE_Username}&pass=${HE_Password}" + body="$body&hosted_dns_zoneid=$_zone_id" + body="$body&menu=edit_zone" + body="$body&hosted_dns_editzone=" + _record_id=$(_post $body "https://dns.he.net/" \ | grep -A 1 "data=\"\("\)\?${_txt_value}\("\)\?\"" \ | tail -n 1 \ | _egrep_o "'[[:digit:]]+','[^']+','TXT'" \ @@ -74,15 +76,15 @@ dns_he_rm() { | head -n1) # ... oh my, what have I done... # Remove the record - curl -L --silent --show-error --cookie "$_he_cookie" \ - --form "menu=edit_zone" \ - --form "hosted_dns_zoneid=$_zone_id" \ - --form "hosted_dns_recordid=$_record_id" \ - --form "hosted_dns_editzone=1" \ - --form "hosted_dns_delrecord=1" \ - --form "hosted_dns_delconfirm=delete" \ - --form "hosted_dns_editzone=1" \ - "https://dns.he.net/" \ + body="email=${HE_Username}&pass=${HE_Password}" + body="$body&menu=edit_zone" + body="$body&hosted_dns_zoneid=$_zone_id" + body="$body&hosted_dns_recordid=$_record_id" + body="$body&hosted_dns_editzone=1" + body="$body&hosted_dns_delrecord=1" + body="$body&hosted_dns_delconfirm=delete" + body="$body&hosted_dns_editzone=1" + _post $body "https://dns.he.net/" \ | grep '
Successfully removed record.
' \ > /dev/null if [ $? -eq 0 ]; then @@ -98,41 +100,10 @@ dns_he_rm() { ########################## PRIVATE FUNCTIONS ########################### -#-- _find_zone() ------------------------------------------------------- - -# Usage: _authenticate -# -# - needs $HE_Username and $HE_Password -# - sets the $_he_cookie - -_authenticate() { - if [ -z "$HE_Username" ] && [ -z "$HE_Password" ]; then - _err \ - 'No auth details provided. Please set user credentials using the \ - \$HE_Username and \$HE_Password envoronment variables.' - return 1 - fi - # Just get a session - _he_cookie=$( \ - curl -L --silent --show-error -I "https://dns.he.net/" \ - | grep '^Set-Cookie:' \ - | _egrep_o 'CGISESSID=[a-z0-9]*') - # Attempt login - curl -L --silent --show-error --cookie "$_he_cookie" \ - --form "email=${HE_Username}" \ - --form "pass=${HE_Password}" \ - "https://dns.he.net/" \ - > /dev/null - # TODO detect unsuccessful logins -} - - #-- _find_zone() ------------------------------------------------------- # Returns the most specific zone found in administration interface. # -# - needs $_he_cookie -# # Example: # # _find_zone first.second.third.co.uk @@ -155,8 +126,9 @@ _find_zone() { ## _all_zones is an array that looks like this: ## ( zone1:id zone2:id ... ) - _all_zones=( $(curl -L --silent --show-error --cookie "$_he_cookie" \ - "https://dns.he.net/" \ + + body="email=${HE_Username}&pass=${HE_Password}" + _all_zones=( $(_post $body "https://dns.he.net/" \ | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" \ | cut -d '"' -f 3,5 --output-delimiter=":" \ ) ) From 8ca45d3d03718c4ba7dc89eb030209ebe2be9ac7 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sun, 23 Jul 2017 05:13:33 +0200 Subject: [PATCH 503/620] Add HE to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5a3a3adf..7d4353c6 100644 --- a/README.md +++ b/README.md @@ -338,6 +338,7 @@ You don't have to do anything manually! 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) And: From f7299403f7b7c0642fee665a7780ef0d8794681f Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sun, 23 Jul 2017 07:31:55 +0200 Subject: [PATCH 504/620] Incorporate Neilpang's comments --- dnsapi/dns_he.sh | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 141268ac..019a7a0b 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -20,7 +20,7 @@ dns_he_add() { _txt_value=$2 _info "Using DNS-01 Hurricane Electric hook" - if [ -z "$HE_Username" ] && [ -z "$HE_Password" ]; then + if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then _err \ 'No auth details provided. Please set user credentials using the \ \$HE_Username and \$HE_Password envoronment variables.' @@ -46,7 +46,8 @@ dns_he_add() { body="$body&Content=$_txt_value" body="$body&TTL=300" body="$body&hosted_dns_editrecord=Submit" - _post $body "https://dns.he.net/" >/dev/null + response="$(_post $body "https://dns.he.net/")" + _debug2 response "$response" } @@ -68,12 +69,14 @@ dns_he_rm() { body="$body&menu=edit_zone" body="$body&hosted_dns_editzone=" _record_id=$(_post $body "https://dns.he.net/" \ - | grep -A 1 "data=\"\("\)\?${_txt_value}\("\)\?\"" \ - | tail -n 1 \ - | _egrep_o "'[[:digit:]]+','[^']+','TXT'" \ - | cut -b 2- \ - | _egrep_o "[[:digit:]]+" \ - | head -n1) # ... oh my, what have I done... + | tr -d '\n' \ + | _egrep_o "data=\""${_txt_value}"([^>]+>){6}[^<]+<[^;]+;deleteRecord\('[0-9]+','${_full_domain}','TXT'\)" \ + | _egrep_o "[0-9]+','${_full_domain}','TXT'\)$" \ + | _egrep_o "^[0-9]+" + ) + # The series of egreps above could have been done a bit shorter but + # I wanted to double-check whether it's the correct record (in case + # HE changes their website somehow). # Remove the record body="email=${HE_Username}&pass=${HE_Password}" @@ -134,12 +137,12 @@ _find_zone() { ) ) _strip_counter=1 - while [ true ] + while true do _attempted_zone=$(echo $_domain | cut -d . -f ${_strip_counter}-) # All possible zone names have been tried - if [ "$_attempted_zone" == "" ] + if [ -z "$_attempted_zone" ] then _err "No zone for domain \"$_domain\" found." break @@ -151,7 +154,7 @@ _find_zone() { do _zone_name=$(echo $i | cut -d ':' -f 1) _zone_id=$(echo $i | cut -d ':' -f 2) - if [ "$_zone_name" == "$_attempted_zone" ] + if [ "$_zone_name" = "$_attempted_zone" ] then # Zone found - we got $_zone_name and $_zone_id, let's get out... _debug "Found relevant zone \"$_zone_name\" with id" \ @@ -162,7 +165,7 @@ _find_zone() { _debug "Zone \"$_attempted_zone\" doesn't exist, let's try another \ variation." - _strip_counter=$(expr $_strip_counter + 1) + _strip_counter=$(_math $_strip_counter + 1) done # No zone found. From 3281043e2784154345b10aef7b107893ea7ff78b Mon Sep 17 00:00:00 2001 From: Brian Candler Date: Tue, 25 Jul 2017 09:39:15 +0100 Subject: [PATCH 505/620] Clarify keylength parameter to _isEccKey() and _initpath() Closes #950 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 486f8678..38965ddc 100755 --- a/acme.sh +++ b/acme.sh @@ -926,7 +926,7 @@ _sign() { } -#keylength +#keylength or isEcc flag (empty str => not ecc) _isEccKey() { _length="$1" @@ -2251,7 +2251,7 @@ _initAPI() { _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" } -#[domain] [keylength] +#[domain] [keylength or isEcc flag] _initpath() { __initHome From 29b21b828b01b37ad9f6536cba27af79a1f6aac3 Mon Sep 17 00:00:00 2001 From: Jeremy Knope Date: Wed, 26 Jul 2017 09:44:11 -0400 Subject: [PATCH 506/620] Fix DNS API scripts on *BSD \n isn't available in all regex/sed --- dnsapi/dns_ad.sh | 3 ++- dnsapi/dns_do.sh | 6 ++++-- dnsapi/dns_freedns.sh | 6 ++++-- dnsapi/dns_linode.sh | 6 ++++-- dnsapi/dns_vscale.sh | 3 ++- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index fc4a664b..79b8c2ab 100755 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -92,7 +92,8 @@ _get_root() { p=1 if _ad_rest GET "domain/"; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + response="$(echo "$response" | tr -d "\n" | sed 's/{/\ +&/g')" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug h "$h" diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index 3a2f8f49..fb6d7dec 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -69,9 +69,11 @@ _dns_do_list_rrs() { fi _rr_list="$(echo "${response}" \ | tr -d "\n\r\t" \ - | sed -e 's//\n/g' \ + | sed -e 's//\ +/g' \ | grep ">$(_regexcape "$fulldomain")" \ - | sed -e 's/<\/item>/\n/g' \ + | sed -e 's/<\/item>/\ +/g' \ | grep '>id[0-9]{1,16}<' \ | tr -d '><')" diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 53da4118..d9677632 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -77,7 +77,8 @@ dns_freedns_add() { | grep -i -e ']*>/\n/Ig' \ + | sed 's/<\/TR[^>]*>/\ +/Ig' \ | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ @@ -216,7 +217,8 @@ dns_freedns_rm() { | grep -i -e ']*>/\n/Ig' \ + | sed 's/<\/TR[^>]*>/\ +/Ig' \ | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index 6d54e6c1..d84ad5fb 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -68,7 +68,8 @@ dns_linode_rm() { _parameters="&DomainID=$_domain_id" if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + response="$(echo "$response" | tr -d "\n" | sed 's/{/\ +&/g')" resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" if [ "$resource" ]; then @@ -128,7 +129,8 @@ _get_root() { p=1 if _rest GET "domain.list"; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + response="$(echo "$response" | tr -d "\n" | sed 's/{/\ +&/g')" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug h "$h" diff --git a/dnsapi/dns_vscale.sh b/dnsapi/dns_vscale.sh index e50b7d8b..fcd162c9 100755 --- a/dnsapi/dns_vscale.sh +++ b/dnsapi/dns_vscale.sh @@ -93,7 +93,8 @@ _get_root() { p=1 if _vscale_rest GET "domains/"; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + response="$(echo "$response" | tr -d "\n" | sed 's/{/\ +&/g')" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug h "$h" From ff74778dea38ef22fb13fbdf452991c4a70135a1 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Wed, 26 Jul 2017 20:15:34 +0200 Subject: [PATCH 507/620] Fix few issues from Travis --- dnsapi/dns_he.sh | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 019a7a0b..1a6f8dbc 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -21,16 +21,14 @@ dns_he_add() { _info "Using DNS-01 Hurricane Electric hook" if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then - _err \ - 'No auth details provided. Please set user credentials using the \ - \$HE_Username and \$HE_Password envoronment variables.' + _err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables." return 1 fi _saveaccountconf HE_Username "$HE_Username" _saveaccountconf HE_Password "$HE_Password" # fills in the $_zone_id - _find_zone $_full_domain || return 1 + _find_zone "$_full_domain" || return 1 _debug "Zone id \"$_zone_id\" will be used." body="email=${HE_Username}&pass=${HE_Password}" @@ -46,11 +44,10 @@ dns_he_add() { body="$body&Content=$_txt_value" body="$body&TTL=300" body="$body&hosted_dns_editrecord=Submit" - response="$(_post $body "https://dns.he.net/")" + response="$(_post "$body" "https://dns.he.net/")" _debug2 response "$response" } - #-- dns_he_rm() - Remove TXT record ------------------------------------ # Usage: dns_he_rm _acme-challenge.subdomain.domain.com "XyZ123..." @@ -60,7 +57,7 @@ dns_he_rm() { _info "Cleaning up after DNS-01 Hurricane Electric hook" # fills in the $_zone_id - _find_zone $_full_domain || return 1 + _find_zone "$_full_domain" || return 1 _debug "Zone id \"$_zone_id\" will be used." # Find the record id to clean @@ -68,7 +65,7 @@ dns_he_rm() { body="$body&hosted_dns_zoneid=$_zone_id" body="$body&menu=edit_zone" body="$body&hosted_dns_editzone=" - _record_id=$(_post $body "https://dns.he.net/" \ + _record_id=$(_post "$body" "https://dns.he.net/" \ | tr -d '\n' \ | _egrep_o "data=\""${_txt_value}"([^>]+>){6}[^<]+<[^;]+;deleteRecord\('[0-9]+','${_full_domain}','TXT'\)" \ | _egrep_o "[0-9]+','${_full_domain}','TXT'\)$" \ @@ -87,9 +84,9 @@ dns_he_rm() { body="$body&hosted_dns_delrecord=1" body="$body&hosted_dns_delconfirm=delete" body="$body&hosted_dns_editzone=1" - _post $body "https://dns.he.net/" \ + _post "$body" "https://dns.he.net/" \ | grep '
Successfully removed record.
' \ - > /dev/null + >/dev/null if [ $? -eq 0 ]; then _info "Record removed successfuly." else @@ -99,12 +96,9 @@ dns_he_rm() { fi } - ########################## PRIVATE FUNCTIONS ########################### - #-- _find_zone() ------------------------------------------------------- - # Returns the most specific zone found in administration interface. # # Example: @@ -131,31 +125,28 @@ _find_zone() { ## ( zone1:id zone2:id ... ) body="email=${HE_Username}&pass=${HE_Password}" - _all_zones=( $(_post $body "https://dns.he.net/" \ + # TODO arrays aren't supported in POSIX sh + _all_zones=($(_post $body "https://dns.he.net/" \ | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" \ - | cut -d '"' -f 3,5 --output-delimiter=":" \ - ) ) + | cut -d '"' -f 3,5 --output-delimiter=":" + )) _strip_counter=1 - while true - do - _attempted_zone=$(echo $_domain | cut -d . -f ${_strip_counter}-) + while true; do + _attempted_zone=$(echo "$_domain" | cut -d . -f ${_strip_counter}-) # All possible zone names have been tried - if [ -z "$_attempted_zone" ] - then + if [ -z "$_attempted_zone" ]; then _err "No zone for domain \"$_domain\" found." break fi # Walk through all zones on the account #echo "$_all_zones" | while IFS=' ' read _zone_name _zone_id - for i in ${_all_zones[@]} - do - _zone_name=$(echo $i | cut -d ':' -f 1) - _zone_id=$(echo $i | cut -d ':' -f 2) - if [ "$_zone_name" = "$_attempted_zone" ] - then + for i in ${_all_zones[@]}; do + _zone_name=$(echo "$i" | cut -d ':' -f 1) + _zone_id=$(echo "$i" | cut -d ':' -f 2) + if [ "$_zone_name" = "$_attempted_zone" ]; then # Zone found - we got $_zone_name and $_zone_id, let's get out... _debug "Found relevant zone \"$_zone_name\" with id" \ "\"$_zone_id\" - will be used for domain \"$_domain\"." From 1546b7e5a971578cef11f960a44aadad3a45b754 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Wed, 26 Jul 2017 20:21:36 +0200 Subject: [PATCH 508/620] Missing quotes --- dnsapi/dns_he.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 1a6f8dbc..3e23b2e0 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -126,7 +126,7 @@ _find_zone() { body="email=${HE_Username}&pass=${HE_Password}" # TODO arrays aren't supported in POSIX sh - _all_zones=($(_post $body "https://dns.he.net/" \ + _all_zones=($(_post "$body" "https://dns.he.net/" \ | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" \ | cut -d '"' -f 3,5 --output-delimiter=":" )) From d39649f30d6718d7b0ec7e1e746a518b23bfd9be Mon Sep 17 00:00:00 2001 From: Jeremy Knope Date: Thu, 27 Jul 2017 08:52:46 -0400 Subject: [PATCH 509/620] Revert non-linode scripts since they're untested --- dnsapi/dns_ad.sh | 3 +-- dnsapi/dns_do.sh | 6 ++---- dnsapi/dns_freedns.sh | 6 ++---- dnsapi/dns_vscale.sh | 3 +-- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/dnsapi/dns_ad.sh b/dnsapi/dns_ad.sh index 79b8c2ab..fc4a664b 100755 --- a/dnsapi/dns_ad.sh +++ b/dnsapi/dns_ad.sh @@ -92,8 +92,7 @@ _get_root() { p=1 if _ad_rest GET "domain/"; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\ -&/g')" + response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug h "$h" diff --git a/dnsapi/dns_do.sh b/dnsapi/dns_do.sh index fb6d7dec..3a2f8f49 100755 --- a/dnsapi/dns_do.sh +++ b/dnsapi/dns_do.sh @@ -69,11 +69,9 @@ _dns_do_list_rrs() { fi _rr_list="$(echo "${response}" \ | tr -d "\n\r\t" \ - | sed -e 's//\ -/g' \ + | sed -e 's//\n/g' \ | grep ">$(_regexcape "$fulldomain")" \ - | sed -e 's/<\/item>/\ -/g' \ + | sed -e 's/<\/item>/\n/g' \ | grep '>id[0-9]{1,16}<' \ | tr -d '><')" diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index d9677632..53da4118 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -77,8 +77,7 @@ dns_freedns_add() { | grep -i -e ']*>/\ -/Ig' \ + | sed 's/<\/TR[^>]*>/\n/Ig' \ | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ @@ -217,8 +216,7 @@ dns_freedns_rm() { | grep -i -e ']*>/\ -/Ig' \ + | sed 's/<\/TR[^>]*>/\n/Ig' \ | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ diff --git a/dnsapi/dns_vscale.sh b/dnsapi/dns_vscale.sh index fcd162c9..e50b7d8b 100755 --- a/dnsapi/dns_vscale.sh +++ b/dnsapi/dns_vscale.sh @@ -93,8 +93,7 @@ _get_root() { p=1 if _vscale_rest GET "domains/"; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\ -&/g')" + response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug h "$h" From aefed1d1b9a5264f460aa94e119cb8a40f8bdddd Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Thu, 27 Jul 2017 18:04:53 +0200 Subject: [PATCH 510/620] Get rid of shell arrays. --- dnsapi/dns_he.sh | 73 +++++++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 3e23b2e0..ada5f794 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -121,16 +121,19 @@ _find_zone() { _domain="$1" - ## _all_zones is an array that looks like this: - ## ( zone1:id zone2:id ... ) - body="email=${HE_Username}&pass=${HE_Password}" - # TODO arrays aren't supported in POSIX sh - _all_zones=($(_post "$body" "https://dns.he.net/" \ - | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" \ - | cut -d '"' -f 3,5 --output-delimiter=":" - )) - + _matches=$(_post "$body" "https://dns.he.net/" \ + | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" + ) + # Zone names and zone IDs are in same order + _zone_ids=$(echo "$_matches" | cut -d '"' -f 5 --output-delimiter=":") + _zone_names=$(echo "$_matches" | cut -d '"' -f 3 --output-delimiter=":") + _debug2 "These are the zones on this HE account:" + _debug2 "$_zone_names" + _debug2 "And these are their respective IDs:" + _debug2 "$_zone_ids" + + # Walk through all possible zone names _strip_counter=1 while true; do _attempted_zone=$(echo "$_domain" | cut -d . -f ${_strip_counter}-) @@ -138,28 +141,46 @@ _find_zone() { # All possible zone names have been tried if [ -z "$_attempted_zone" ]; then _err "No zone for domain \"$_domain\" found." - break + return 1 fi - # Walk through all zones on the account - #echo "$_all_zones" | while IFS=' ' read _zone_name _zone_id - for i in ${_all_zones[@]}; do - _zone_name=$(echo "$i" | cut -d ':' -f 1) - _zone_id=$(echo "$i" | cut -d ':' -f 2) - if [ "$_zone_name" = "$_attempted_zone" ]; then - # Zone found - we got $_zone_name and $_zone_id, let's get out... - _debug "Found relevant zone \"$_zone_name\" with id" \ - "\"$_zone_id\" - will be used for domain \"$_domain\"." - return 0 - fi - done - - _debug "Zone \"$_attempted_zone\" doesn't exist, let's try another \ - variation." + _debug "Looking for zone \"${_attempted_zone}\"" + _line_num=$(echo "$_zone_names" | _find_linenum "$_attempted_zone") + if [ -n "$_line_num" ]; then + _zone_id=$(echo "$_zone_ids" | sed "${_line_num}q;d") + _debug "Found relevant zone \"$_attempted_zone\" with id" \ + "\"$_zone_id\" - will be used for domain \"$_domain\"." + return 0 + fi + + _debug "Zone \"$_attempted_zone\" doesn't exist, let's try a less" \ + "specific zone." _strip_counter=$(_math $_strip_counter + 1) done +} - # No zone found. +#-- _find_linenum()----------------------------------------------------- +# Returns line number of line (supplied as an argument) in STDIN. +# +# Example: +# +# printf "a\nb\nc" | _find_linenum "b" +# +# This will: +# - print out 2 because that's the line number of "b" +# - return code 0 because it was found + +_find_linenum() { + _current_line_num=0 + while read line; do + _current_line_num=$(expr "$_current_line_num" + 1) + if [ "$line" = "$1" ]; then + # Found! Let's echo the line number and quit + echo $_current_line_num + return 0 + fi + done + # Not found return 1 } From 235b5b0c154331879b70fd149d1fe7df19eac4c8 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Thu, 27 Jul 2017 18:06:19 +0200 Subject: [PATCH 511/620] Small cosmetic fixes. --- dnsapi/dns_he.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index ada5f794..51418aa9 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -11,7 +11,6 @@ # Author: Ondrej Simek # Git repo: https://github.com/angel333/acme.sh - #-- dns_he_add() - Add TXT record -------------------------------------- # Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..." @@ -86,7 +85,7 @@ dns_he_rm() { body="$body&hosted_dns_editzone=1" _post "$body" "https://dns.he.net/" \ | grep '
Successfully removed record.
' \ - >/dev/null + >/dev/null if [ $? -eq 0 ]; then _info "Record removed successfuly." else From 577380e98e33c32f87d74df07d0d9d862b89b5be Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Thu, 27 Jul 2017 18:44:55 +0200 Subject: [PATCH 512/620] Few fixes for shellcheck --- dnsapi/dns_he.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 51418aa9..9b789d35 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -154,7 +154,7 @@ _find_zone() { _debug "Zone \"$_attempted_zone\" doesn't exist, let's try a less" \ "specific zone." - _strip_counter=$(_math $_strip_counter + 1) + _strip_counter=$(_math "$_strip_counter" + 1) done } @@ -171,11 +171,11 @@ _find_zone() { _find_linenum() { _current_line_num=0 - while read line; do - _current_line_num=$(expr "$_current_line_num" + 1) + while read -r line; do + _current_line_num=$(_math "$_current_line_num" + 1) if [ "$line" = "$1" ]; then # Found! Let's echo the line number and quit - echo $_current_line_num + echo "$_current_line_num" return 0 fi done From 8e6cf669ad01905d4d9e22f7a2874dcba8c7e263 Mon Sep 17 00:00:00 2001 From: Jeremy Knope Date: Thu, 27 Jul 2017 14:15:19 -0400 Subject: [PATCH 513/620] Try awk instead for \n replacements --- dnsapi/dns_linode.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index d84ad5fb..ee3b1c8b 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -68,8 +68,7 @@ dns_linode_rm() { _parameters="&DomainID=$_domain_id" if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\ -&/g')" + response="$(echo "$response" | tr -d "\n" | awk '{ gsub("{","\n{",$1); print $1 }')" resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" if [ "$resource" ]; then @@ -129,8 +128,7 @@ _get_root() { p=1 if _rest GET "domain.list"; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\ -&/g')" + response="$(echo "$response" | tr -d "\n" | awk '{ gsub("{","\n{",$1); print $1 }')" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug h "$h" From 8534e3b2f7fd16477b811c262f60e9b63cb85e32 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Fri, 28 Jul 2017 13:58:47 +0200 Subject: [PATCH 514/620] Make shellcheck happier --- dnsapi/dns_he.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 9b789d35..3ca00af9 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -20,6 +20,8 @@ dns_he_add() { _info "Using DNS-01 Hurricane Electric hook" if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then + HE_Username= + HE_Password= _err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password envoronment variables." return 1 fi From d6780f9e49f18bf503f46c5d4859289e593935c0 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Fri, 28 Jul 2017 15:29:35 +0200 Subject: [PATCH 515/620] Retain an exit code --- dnsapi/dns_he.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 3ca00af9..ab4393c7 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -46,7 +46,9 @@ dns_he_add() { body="$body&TTL=300" body="$body&hosted_dns_editrecord=Submit" response="$(_post "$body" "https://dns.he.net/")" + exitcode=$? _debug2 response "$response" + return $exitvalue } #-- dns_he_rm() - Remove TXT record ------------------------------------ From ab1efd923b56b9014f07e7fcac7a81325d93d0b8 Mon Sep 17 00:00:00 2001 From: Jeremy Knope Date: Fri, 28 Jul 2017 10:26:56 -0400 Subject: [PATCH 516/620] back to sed --- dnsapi/dns_linode.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index ee3b1c8b..00634d5d 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -68,7 +68,7 @@ dns_linode_rm() { _parameters="&DomainID=$_domain_id" if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then - response="$(echo "$response" | tr -d "\n" | awk '{ gsub("{","\n{",$1); print $1 }')" + response="$(echo "$response" | tr -d "\n" | sed $'s/{/\\\n&/g')" resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" if [ "$resource" ]; then @@ -128,7 +128,7 @@ _get_root() { p=1 if _rest GET "domain.list"; then - response="$(echo "$response" | tr -d "\n" | awk '{ gsub("{","\n{",$1); print $1 }')" + response="$(echo "$response" | tr -d "\n" | sed $'s/{/\\\n&/g')" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) _debug h "$h" From ccf9a9976c1b7cf31c60a4b74ead0f30fba1de28 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Fri, 28 Jul 2017 18:33:25 +0200 Subject: [PATCH 517/620] Fix the previous rushed commit. --- dnsapi/dns_he.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index ab4393c7..2fb1101e 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -46,9 +46,14 @@ dns_he_add() { body="$body&TTL=300" body="$body&hosted_dns_editrecord=Submit" response="$(_post "$body" "https://dns.he.net/")" - exitcode=$? + exit_code="$?" + if [ "$exit_code" -eq 0 ]; then + _info "TXT record added successfuly." + else + _err "Couldn't add the TXT record." + return "$exit_code" + fi _debug2 response "$response" - return $exitvalue } #-- dns_he_rm() - Remove TXT record ------------------------------------ @@ -90,7 +95,7 @@ dns_he_rm() { _post "$body" "https://dns.he.net/" \ | grep '
Successfully removed record.
' \ >/dev/null - if [ $? -eq 0 ]; then + if [ "$?" -eq 0 ]; then _info "Record removed successfuly." else _err \ From a5c56c547d024493bb90732cda20108d09392715 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 29 Jul 2017 15:23:31 +0800 Subject: [PATCH 518/620] minor, fix dns param --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 38965ddc..9486bcc5 100755 --- a/acme.sh +++ b/acme.sh @@ -5440,7 +5440,7 @@ _process() { ;; --dns) wvalue="dns" - if ! _startswith "$2" "-"; then + if [ "$2" ] && ! _startswith "$2" "-"; then wvalue="$2" shift fi From 31b67ab92efd23802acb8510126418b83e1af8db Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sat, 29 Jul 2017 13:52:28 +0200 Subject: [PATCH 519/620] Few non-critical fixes. --- dnsapi/dns_he.sh | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 2fb1101e..a160e16a 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -28,13 +28,12 @@ dns_he_add() { _saveaccountconf HE_Username "$HE_Username" _saveaccountconf HE_Password "$HE_Password" - # fills in the $_zone_id + # Fills in the $_zone_id _find_zone "$_full_domain" || return 1 _debug "Zone id \"$_zone_id\" will be used." body="email=${HE_Username}&pass=${HE_Password}" body="$body&account=" - body="$body&account=" body="$body&menu=edit_zone" body="$body&Type=TXT" body="$body&hosted_dns_zoneid=$_zone_id" @@ -91,16 +90,13 @@ dns_he_rm() { body="$body&hosted_dns_editzone=1" body="$body&hosted_dns_delrecord=1" body="$body&hosted_dns_delconfirm=delete" - body="$body&hosted_dns_editzone=1" _post "$body" "https://dns.he.net/" \ | grep '
Successfully removed record.
' \ >/dev/null if [ "$?" -eq 0 ]; then _info "Record removed successfuly." else - _err \ - "Could not clean (remove) up the record. Please go to HE" \ - "administration interface and clean it by hand." + _err "Could not clean (remove) up the record. Please go to HE administration interface and clean it by hand." fi } @@ -134,8 +130,8 @@ _find_zone() { | _egrep_o "delete_dom.*name=\"[^\"]+\" value=\"[0-9]+" ) # Zone names and zone IDs are in same order - _zone_ids=$(echo "$_matches" | cut -d '"' -f 5 --output-delimiter=":") - _zone_names=$(echo "$_matches" | cut -d '"' -f 3 --output-delimiter=":") + _zone_ids=$(echo "$_matches" | cut -d '"' -f 5) + _zone_names=$(echo "$_matches" | cut -d '"' -f 3) _debug2 "These are the zones on this HE account:" _debug2 "$_zone_names" _debug2 "And these are their respective IDs:" @@ -156,13 +152,11 @@ _find_zone() { _line_num=$(echo "$_zone_names" | _find_linenum "$_attempted_zone") if [ -n "$_line_num" ]; then _zone_id=$(echo "$_zone_ids" | sed "${_line_num}q;d") - _debug "Found relevant zone \"$_attempted_zone\" with id" \ - "\"$_zone_id\" - will be used for domain \"$_domain\"." + _debug "Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"." return 0 fi - _debug "Zone \"$_attempted_zone\" doesn't exist, let's try a less" \ - "specific zone." + _debug "Zone \"$_attempted_zone\" doesn't exist, let's try a less specific zone." _strip_counter=$(_math "$_strip_counter" + 1) done } From a25b2af66cd6a4c69ee673ec32aaebd068079042 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sat, 29 Jul 2017 14:25:07 +0200 Subject: [PATCH 520/620] Get rid of _find_num --- dnsapi/dns_he.sh | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index a160e16a..7dde55d4 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -149,9 +149,18 @@ _find_zone() { fi _debug "Looking for zone \"${_attempted_zone}\"" - _line_num=$(echo "$_zone_names" | _find_linenum "$_attempted_zone") - if [ -n "$_line_num" ]; then - _zone_id=$(echo "$_zone_ids" | sed "${_line_num}q;d") + + # Take care of "." and only match whole lines. Note that grep -F + # cannot be used because there's no way to make it match whole + # lines. + regex="^$(echo "$_attempted_zone" | sed 's/\./\\./g')$" + line_num=$(echo "$_zone_names" \ + | grep -n "$regex" \ + | cut -d : -f 1 + ) + + if [ -n "$line_num" ]; then + _zone_id=$(echo "$_zone_ids" | sed "${line_num}q;d") _debug "Found relevant zone \"$_attempted_zone\" with id \"$_zone_id\" - will be used for domain \"$_domain\"." return 0 fi @@ -160,30 +169,4 @@ _find_zone() { _strip_counter=$(_math "$_strip_counter" + 1) done } - -#-- _find_linenum()----------------------------------------------------- -# Returns line number of line (supplied as an argument) in STDIN. -# -# Example: -# -# printf "a\nb\nc" | _find_linenum "b" -# -# This will: -# - print out 2 because that's the line number of "b" -# - return code 0 because it was found - -_find_linenum() { - _current_line_num=0 - while read -r line; do - _current_line_num=$(_math "$_current_line_num" + 1) - if [ "$line" = "$1" ]; then - # Found! Let's echo the line number and quit - echo "$_current_line_num" - return 0 - fi - done - # Not found - return 1 -} - # vim: et:ts=2:sw=2: From f438ff4bab695818932149d5b6bcecb1b6bed712 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sat, 29 Jul 2017 14:29:13 +0200 Subject: [PATCH 521/620] Fix an improbable corner case. --- dnsapi/dns_he.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 7dde55d4..152d469c 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -72,10 +72,11 @@ dns_he_rm() { body="$body&hosted_dns_zoneid=$_zone_id" body="$body&menu=edit_zone" body="$body&hosted_dns_editzone=" + domain_regex="$(echo "$_full_domain" | sed 's/\./\\./g')" # escape dots _record_id=$(_post "$body" "https://dns.he.net/" \ | tr -d '\n' \ - | _egrep_o "data=\""${_txt_value}"([^>]+>){6}[^<]+<[^;]+;deleteRecord\('[0-9]+','${_full_domain}','TXT'\)" \ - | _egrep_o "[0-9]+','${_full_domain}','TXT'\)$" \ + | _egrep_o "data=\""${_txt_value}"([^>]+>){6}[^<]+<[^;]+;deleteRecord\('[0-9]+','${domain_regex}','TXT'\)" \ + | _egrep_o "[0-9]+','${domain_regex}','TXT'\)$" \ | _egrep_o "^[0-9]+" ) # The series of egreps above could have been done a bit shorter but From baa1160594921e465ee798b77c5add4ed6b1d907 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sat, 29 Jul 2017 14:31:27 +0200 Subject: [PATCH 522/620] Make Shellcheck happier about exit codes --- 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 152d469c..3a1e6979 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -94,10 +94,12 @@ dns_he_rm() { _post "$body" "https://dns.he.net/" \ | grep '
Successfully removed record.
' \ >/dev/null - if [ "$?" -eq 0 ]; then + exit_code="$?" + if [ "$exit_code" -eq 0 ]; then _info "Record removed successfuly." else _err "Could not clean (remove) up the record. Please go to HE administration interface and clean it by hand." + return "$exit_code" fi } From 4dd69a8b1adaacfbb5a4894a8a5fc0403e3b4e88 Mon Sep 17 00:00:00 2001 From: Ondrej Simek Date: Sat, 29 Jul 2017 14:40:56 +0200 Subject: [PATCH 523/620] Exit codes, exit codes... Exit codes everywhere... --- dnsapi/dns_he.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 3a1e6979..7d86eb7a 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -50,9 +50,9 @@ dns_he_add() { _info "TXT record added successfuly." else _err "Couldn't add the TXT record." - return "$exit_code" fi _debug2 response "$response" + return "$exit_code" } #-- dns_he_rm() - Remove TXT record ------------------------------------ From 8eab77f3c607075ff1cd59b59f76b074f1d46605 Mon Sep 17 00:00:00 2001 From: Brian Candler Date: Mon, 24 Jul 2017 14:23:01 +0100 Subject: [PATCH 524/620] Add deployment script for unifi controller --- acme.sh | 28 +++++++++++--- deploy/unifi.sh | 100 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 deploy/unifi.sh diff --git a/acme.sh b/acme.sh index 9486bcc5..60eef4bb 100755 --- a/acme.sh +++ b/acme.sh @@ -1182,6 +1182,28 @@ _ss() { return 1 } +#outfile key cert cacert [password [name [caname]]] +_toPkcs() { + _cpfx="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + pfxPassword="$5" + pfxName="$6" + pfxCaname="$7" + + if [ "$pfxCaname" ]; then + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName" -caname "$pfxCaname" + elif [ "$pfxName" ]; then + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName" + elif [ "$pfxPassword" ]; then + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" + else + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" + fi + +} + #domain [password] [isEcc] toPkcs() { domain="$1" @@ -1195,11 +1217,7 @@ toPkcs() { _initpath "$domain" "$_isEcc" - if [ "$pfxPassword" ]; then - ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" - else - ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" - fi + _toPkcs "$CERT_PFX_PATH" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$pfxPassword" if [ "$?" = "0" ]; then _info "Success, Pfx is exported to: $CERT_PFX_PATH" diff --git a/deploy/unifi.sh b/deploy/unifi.sh new file mode 100644 index 00000000..184aa62e --- /dev/null +++ b/deploy/unifi.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to unifi server. + +#returns 0 means success, otherwise error. + +#DEPLOY_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore" +#DEPLOY_UNIFI_KEYPASS="aircontrolenterprise" +#DEPLOY_UNIFI_RELOAD="service unifi restart" + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +unifi_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if ! _exists keytool; then + _err "keytool not found" + return 1 + fi + + DEFAULT_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore" + _unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-$DEFAULT_UNIFI_KEYSTORE}" + DEFAULT_UNIFI_KEYPASS="aircontrolenterprise" + _unifi_keypass="${DEPLOY_UNIFI_KEYPASS:-$DEFAULT_UNIFI_KEYPASS}" + DEFAULT_UNIFI_RELOAD="service unifi restart" + _reload="${DEPLOY_UNIFI_RELOAD:-$DEFAULT_UNIFI_RELOAD}" + + _debug _unifi_keystore "$_unifi_keystore" + if [ ! -f "$_unifi_keystore" ]; then + if [ -z "$DEPLOY_UNIFI_KEYSTORE" ]; then + _err "unifi keystore is not found, please define DEPLOY_UNIFI_KEYSTORE" + return 1 + else + _err "It seems that the specified unifi keystore is not valid, please check." + return 1 + fi + fi + if [ ! -w "$_unifi_keystore" ]; then + _err "The file $_unifi_keystore is not writable, please change the permission." + return 1 + fi + + _info "Generate import pkcs12" + _import_pkcs12="$(_mktemp)" + _toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root + if [ "$?" != "0" ]; then + _err "Oops, error creating import pkcs12, please report bug to us." + return 1 + fi + + _info "Modify unifi keystore: $_unifi_keystore" + if keytool -importkeystore \ + -deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \ + -srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \ + -alias unifi -noprompt; then + _info "Import keystore success!" + rm "$_import_pkcs12" + else + _err "Import unifi keystore error, please report bug to us." + rm "$_import_pkcs12" + return 1 + fi + + _info "Run reload: $_reload" + if eval "$_reload"; then + _info "Reload success!" + if [ "$DEPLOY_UNIFI_KEYSTORE" ]; then + _savedomainconf DEPLOY_UNIFI_KEYSTORE "$DEPLOY_UNIFI_KEYSTORE" + else + _cleardomainconf DEPLOY_UNIFI_KEYSTORE + fi + if [ "$DEPLOY_UNIFI_KEYPASS" ]; then + _savedomainconf DEPLOY_UNIFI_KEYPASS "$DEPLOY_UNIFI_KEYPASS" + else + _cleardomainconf DEPLOY_UNIFI_KEYPASS + fi + if [ "$DEPLOY_UNIFI_RELOAD" ]; then + _savedomainconf DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD" + else + _cleardomainconf DEPLOY_UNIFI_RELOAD + fi + return 0 + else + _err "Reload error" + return 1 + fi + return 0 + +} From cd3a4573f26c03315121f505ac97b45c511d9cb9 Mon Sep 17 00:00:00 2001 From: Jeremy Knope Date: Mon, 31 Jul 2017 08:37:30 -0400 Subject: [PATCH 525/620] Fix shell check errors --- dnsapi/dns_linode.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index 00634d5d..26ca53e4 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -68,7 +68,7 @@ dns_linode_rm() { _parameters="&DomainID=$_domain_id" if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then - response="$(echo "$response" | tr -d "\n" | sed $'s/{/\\\n&/g')" + response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" if [ "$resource" ]; then @@ -128,7 +128,7 @@ _get_root() { p=1 if _rest GET "domain.list"; then - response="$(echo "$response" | tr -d "\n" | sed $'s/{/\\\n&/g')" + 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" From c145f24621455f8608c179fc253d1fd00244bb6f Mon Sep 17 00:00:00 2001 From: Jeremy Knope Date: Thu, 3 Aug 2017 09:47:45 -0400 Subject: [PATCH 526/620] Remove extra space --- dnsapi/dns_linode.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_linode.sh b/dnsapi/dns_linode.sh index 26ca53e4..ead5b164 100755 --- a/dnsapi/dns_linode.sh +++ b/dnsapi/dns_linode.sh @@ -68,7 +68,7 @@ dns_linode_rm() { _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")" + response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" if [ "$resource" ]; then @@ -128,7 +128,7 @@ _get_root() { p=1 if _rest GET "domain.list"; then - response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" + 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" From 5c3b41bd93c2c4e6da40c445cd5f15a1ba3f7274 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 4 Aug 2017 21:57:45 +0800 Subject: [PATCH 527/620] format --- dnsapi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 0888517b..b3b6344e 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -585,7 +585,7 @@ 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 +## 31. Use Hurricane Electric Hurricane Electric doesn't have an API so just set your login credentials like so: From 415f375ce6f0de5a20545ba7ff6a9a7aa044c484 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 10 Aug 2017 21:31:28 +0800 Subject: [PATCH 528/620] support fcrontab, fix https://github.com/Neilpang/acme.sh/issues/966 --- acme.sh | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/acme.sh b/acme.sh index 60eef4bb..fe884e33 100755 --- a/acme.sh +++ b/acme.sh @@ -4417,15 +4417,19 @@ _installcert() { installcronjob() { _c_home="$1" _initpath - if ! _exists "crontab"; then - _err "crontab doesn't exist, so, we can not install cron jobs." + _CRONTAB="crontab" + if ! _exists "$_CRONTAB" && _exists "fcrontab"; then + _CRONTAB="fcrontab" + fi + if ! _exists "$_CRONTAB"; then + _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 ! $_CRONTAB -l | grep "$PROJECT_ENTRY --cron"; then if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY" else @@ -4439,15 +4443,15 @@ installcronjob() { _t=$(_time) random_minute=$(_math $_t % 60) if _exists uname && uname -a | grep SunOS >/dev/null; then - crontab -l | { + $_CRONTAB -l | { cat echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null" - } | crontab -- + } | $_CRONTAB -- else - crontab -l | { + $_CRONTAB -l | { cat echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null" - } | crontab - + } | $_CRONTAB - fi fi if [ "$?" != "0" ]; then @@ -4459,16 +4463,21 @@ installcronjob() { } uninstallcronjob() { - if ! _exists "crontab"; then + _CRONTAB="crontab" + if ! _exists "$_CRONTAB" && _exists "fcrontab"; then + _CRONTAB="fcrontab" + fi + + if ! _exists "$_CRONTAB"; then return fi _info "Removing cron job" - cr="$(crontab -l | grep "$PROJECT_ENTRY --cron")" + cr="$($_CRONTAB -l | grep "$PROJECT_ENTRY --cron")" if [ "$cr" ]; then if _exists uname && uname -a | grep solaris >/dev/null; then - crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab -- + $_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB -- else - crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab - + $_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB - fi LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')" _info LE_WORKING_DIR "$LE_WORKING_DIR" @@ -4745,7 +4754,7 @@ _precheck() { fi if [ -z "$_nocron" ]; then - if ! _exists "crontab"; 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." From 96801e3478d64427f8ec0937de1d30ec05b9432a Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Fri, 11 Aug 2017 16:46:29 -0500 Subject: [PATCH 529/620] Update DuckDNS support, fix failure on first call, no longer save the domain/username as a global, and other tweaks --- dnsapi/README.md | 5 +-- dnsapi/dns_duckdns.sh | 79 +++++++++++++++++++++++++++++++------------ 2 files changed, 59 insertions(+), 25 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index b3b6344e..34b38678 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -512,14 +512,11 @@ export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" ``` Please note that since DuckDNS uses StartSSL as their cert provider, thus ---insecure must be used when issuing certs: +--insecure may need to be used when issuing certs: ``` acme.sh --insecure --issue --dns dns_duckdns -d mydomain.duckdns.org ``` -Also, DuckDNS uses the domain name as username for recording changing, so the -account file will always store the lastly used domain name. - For issues, please report to https://github.com/raidenii/acme.sh/issues. ## 28. Use Name.com API diff --git a/dnsapi/dns_duckdns.sh b/dnsapi/dns_duckdns.sh index d6987352..711b81ee 100755 --- a/dnsapi/dns_duckdns.sh +++ b/dnsapi/dns_duckdns.sh @@ -3,11 +3,14 @@ #Created by RaidenII, to use DuckDNS's API to add/remove text records #06/27/2017 -# Currently only support single domain access -# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure must be used with acme.sh +# Pass credentials before "acme.sh --issue --dns dns_duckdns ..." +# -- +# export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" +# -- +# +# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure may need to be used with acme.sh DuckDNS_API="https://www.duckdns.org/update" -API_Params="domains=$DuckDNS_Domain&token=$DuckDNS_Token" ######## Public functions ##################### @@ -16,35 +19,36 @@ dns_duckdns_add() { fulldomain=$1 txtvalue=$2 - # We'll extract the domain/username from full domain - DuckDNS_Domain=$(echo "$fulldomain" | _lower_case | _egrep_o '.[^.]*.duckdns.org' | cut -d . -f 2) - - if [ -z "$DuckDNS_Domain" ]; then - _err "Error extracting the domain." - return 1 - fi - + DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}" if [ -z "$DuckDNS_Token" ]; then - DuckDNS_Token="" + _err "You must export variable: DuckDNS_Token" _err "The token for your DuckDNS account is necessary." _err "You can look it up in your DuckDNS account." return 1 fi # Now save the credentials. - _saveaccountconf DuckDNS_Domain "$DuckDNS_Domain" - _saveaccountconf DuckDNS_Token "$DuckDNS_Token" + _saveaccountconf_mutable DuckDNS_Token "$DuckDNS_Token" # Unfortunately, DuckDNS does not seems to support lookup domain through API # So I assume your credentials (which are your domain and token) are correct # If something goes wrong, we will get a KO response from DuckDNS + if ! _duckdns_get_domain; then + return 1 + fi + # Now add the TXT record to DuckDNS _info "Trying to add TXT record" - if _duckdns_rest GET "$API_Params&txt=$txtvalue" && [ "$response" = "OK" ]; then - _info "TXT record has been successfully added to your DuckDNS domain." - _info "Note that all subdomains under this domain uses the same TXT record." - return 0 + if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=$txtvalue"; then + if [ "$response" = "OK" ]; then + _info "TXT record has been successfully added to your DuckDNS domain." + _info "Note that all subdomains under this domain uses the same TXT record." + return 0 + else + _err "Errors happened during adding the TXT record, response=$response" + return 1 + fi else _err "Errors happened during adding the TXT record." return 1 @@ -57,11 +61,28 @@ dns_duckdns_rm() { fulldomain=$1 txtvalue=$2 + DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}" + if [ -z "$DuckDNS_Token" ]; then + _err "You must export variable: DuckDNS_Token" + _err "The token for your DuckDNS account is necessary." + _err "You can look it up in your DuckDNS account." + return 1 + fi + + if ! _duckdns_get_domain; then + return 1 + fi + # Now remove the TXT record from DuckDNS _info "Trying to remove TXT record" - if _duckdns_rest GET "$API_Params&txt=&clear=true" && [ "$response" = "OK" ]; then - _info "TXT record has been successfully removed from your DuckDNS domain." - return 0 + if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=&clear=true"; then + if [ "$response" = "OK" ]; then + _info "TXT record has been successfully removed from your DuckDNS domain." + return 0 + else + _err "Errors happened during removing the TXT record, response=$response" + return 1 + fi else _err "Errors happened during removing the TXT record." return 1 @@ -70,6 +91,22 @@ dns_duckdns_rm() { #################### Private functions below ################################## +#fulldomain=_acme-challenge.domain.duckdns.org +#returns +# _duckdns_domain=domain +_duckdns_get_domain() { + + # We'll extract the domain/username from full domain + _duckdns_domain="$(printf "%s" "$fulldomain" | _lower_case | _egrep_o '[.][^.][^.]*[.]duckdns.org' | cut -d . -f 2)" + + if [ -z "$_duckdns_domain" ]; then + _err "Error extracting the domain." + return 1 + fi + + return 0 +} + #Usage: method URI _duckdns_rest() { method=$1 From a07395fb563faff04f786e2e352aacf4dc7840ce Mon Sep 17 00:00:00 2001 From: Michele Date: Thu, 17 Aug 2017 12:50:28 +0200 Subject: [PATCH 530/620] Added support for busybox in time2str() awk fallback if none of preceding method works --- acme.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/acme.sh b/acme.sh index fe884e33..9bf9e1e0 100755 --- a/acme.sh +++ b/acme.sh @@ -1367,6 +1367,10 @@ _time2str() { echo "$_t_s_a" fi + #Busybox + if echo "$1" | awk '{ print strftime("%c", $0); }' 2>/dev/null; then + return + fi } _normalizeJson() { From 309bec474f11c1c9a2be472c44818703bfe6d911 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 22 Aug 2017 20:27:13 +0800 Subject: [PATCH 531/620] add warning for dns manual mode --- acme.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/acme.sh b/acme.sh index 9bf9e1e0..cd2f981c 100755 --- a/acme.sh +++ b/acme.sh @@ -100,6 +100,10 @@ _PREPARE_LINK="https://github.com/Neilpang/acme.sh/wiki/Install-preparations" _STATELESS_WIKI="https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode" +_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" + __INTERACTIVE="" if [ -t 1 ]; then __INTERACTIVE="1" @@ -3046,6 +3050,10 @@ _on_issue_err() { ) fi + if [ "$IS_RENEW" = "1" ] && _hasfield "$Le_Webroot" "dns"; then + _err "$_DNS_MANUAL_ERR" + fi + if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then _debug "$(_dlg_versions)" fi @@ -3078,6 +3086,10 @@ _on_issue_success() { fi fi + if _hasfield "$Le_Webroot" "dns"; then + _err "$_DNS_MANUAL_WARN" + fi + } updateaccount() { From 48e9006cd120317b62ee17e207c82517cc629d31 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 25 Aug 2017 20:51:31 +0800 Subject: [PATCH 532/620] fix cpanel uapi --- deploy/README.md | 18 ++++++++++++++++++ deploy/cpanel_uapi.sh | 15 ++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index 232fdb4a..e026cadf 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -80,3 +80,21 @@ acme.sh --deploy -d ftp.example.com --deploy-hook exim4 ```sh acme.sh --deploy -d ftp.example.com --deploy-hook keychain ``` + +## 7. Deploy to cpanel host. + +``` +acme.sh --deploy -d example.com --deploy-hook cpanel_uapi +``` + +If you are login as root, please specify the username to deploy cert to: + +```sh +export DEPLOY_CPANEL_USER=username +acme.sh --deploy -d example.com --deploy-hook cpanel_uapi +``` + + + + + diff --git a/deploy/cpanel_uapi.sh b/deploy/cpanel_uapi.sh index ded50d0c..89ce1988 100644 --- a/deploy/cpanel_uapi.sh +++ b/deploy/cpanel_uapi.sh @@ -11,7 +11,7 @@ #domain keyfile certfile cafile fullchain -cpanel_uapi() { +cpanel_uapi_deploy() { _cdomain="$1" _ckey="$2" _ccert="$3" @@ -24,6 +24,14 @@ cpanel_uapi() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" + if ! _exists uapi; then + _err "The command uapi is not found." + return 1 + fi + if ! _exists php; then + _err "The command php is not found." + return 1 + fi # read cert and key files and urlencode both _certstr=$(cat "$_ccert") _keystr=$(cat "$_ckey") @@ -34,6 +42,11 @@ cpanel_uapi() { _debug _key "$_key" if [ "$(id -u)" = 0 ]; then + if [ -z "$DEPLOY_CPANEL_USER" ]; then + _err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username" + return 1; + fi + _savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER" _response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") else _response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") From a2d6daaef47feec91dcbf4dc1c4caec8630c1484 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 25 Aug 2017 20:54:10 +0800 Subject: [PATCH 533/620] fix cpanel_uapi.sh --- deploy/cpanel_uapi.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/cpanel_uapi.sh b/deploy/cpanel_uapi.sh index 89ce1988..2ba112c4 100644 --- a/deploy/cpanel_uapi.sh +++ b/deploy/cpanel_uapi.sh @@ -44,7 +44,7 @@ cpanel_uapi_deploy() { if [ "$(id -u)" = 0 ]; then if [ -z "$DEPLOY_CPANEL_USER" ]; then _err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username" - return 1; + return 1 fi _savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER" _response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") From 88bb7b780d445d1874611aa841b51bdb153f1bfb Mon Sep 17 00:00:00 2001 From: fritteli Date: Tue, 29 Aug 2017 22:35:11 +0200 Subject: [PATCH 534/620] Typos --- dnsapi/dns_he.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_he.sh b/dnsapi/dns_he.sh index 7d86eb7a..4d1973ad 100755 --- a/dnsapi/dns_he.sh +++ b/dnsapi/dns_he.sh @@ -47,7 +47,7 @@ dns_he_add() { response="$(_post "$body" "https://dns.he.net/")" exit_code="$?" if [ "$exit_code" -eq 0 ]; then - _info "TXT record added successfuly." + _info "TXT record added successfully." else _err "Couldn't add the TXT record." fi @@ -96,7 +96,7 @@ dns_he_rm() { >/dev/null exit_code="$?" if [ "$exit_code" -eq 0 ]; then - _info "Record removed successfuly." + _info "Record removed successfully." else _err "Could not clean (remove) up the record. Please go to HE administration interface and clean it by hand." return "$exit_code" From f6da19ba835e52fba79caec2544aa89af0116c62 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Tue, 29 Aug 2017 23:13:29 +0200 Subject: [PATCH 535/620] add deploy script for the AVM FRITZ!Box --- deploy/fritzbox.sh | 85 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 deploy/fritzbox.sh diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh new file mode 100644 index 00000000..1290dc7a --- /dev/null +++ b/deploy/fritzbox.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to an AVM FRITZ!Box router. + +#returns 0 means success, otherwise error. + +#DEPLOY_FRITZBOX_USERNAME="username" +#DEPLOY_FRITZBOX_PASSWORD="password" +#DEPLOY_FRITZBOX_URL="https://fritz.box" + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +fritzbox_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if ! _exists wget; then + _err "wget not found" + return 1 + fi + if ! exists iconv; then + _err "iconv not found" + return 1 + fi + + _fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}" + _fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}" + _fritzbox_url="${DEPLOY_FRITZBOX_URL}" + + _debug _fritzbox_url "$_fritzbox_url" + _debug _fritzbox_usename "$_fritzbox_username" + _secure_debug _fritzbox_password "$_fritzbox_password" + if [ ! -z "$_fritzbox_username" ]; then + _err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME." + return 1 + fi + if [ ! -z "$_fritzbox_password" ]; then + _err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD." + return 1 + fi + if [ ! -z "$_fritzbox_url" ]; then + _err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL." + return 1 + fi + + _info "Log in in to the FRITZ!Box" + _fritzbox_challenge="$(wget -q -O - ${_fritzbox_url}/login_sid.lua | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" + _fritzbox_hash="$(echo -n ${_fritzbox_challenge}-${_fritzbox_password} | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" + _fritzbox_sid="$(wget -q -O - ${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_frithbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash} | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + + _info "Generate form POST request" + _post_request="$(_mktemp)" + _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" + printf -- "--${_post_boundary}\r\n" >> "${_post_request}" + printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n${_fritzbox_sid}\r\n" >> "${_post_request}" + printf -- "--${_post_boundary}\r\n" >> "${_post_request}" + # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a passwort. But if they ever do, here's the place to use it! + printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n${_CERTPASSWORD_}\r\n" >> "${_post_request}" + printf -- "--${_post_boundary}\r\n" >> "${_post_request}" + printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" >> "${_post_request}" + printf "Content-Type: application/octet-stream\r\n\r\n" >> "${_post_request}" + cat "${_ckey}" >> "${_post_request}" + cat "${_cfullchain}" >> "${_post_request}" + printf "\r\n" >> "${_post_request}" + printf -- "--${_post_boundary}--" >> "${_post_request}" + + _info "Upload certificate to the FRITZ!Box" + wget -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" + + _info "Upload successful" + rm "${_post_request}" + + return 0 +} + From 4bb488258d24159284fc55b5b81d7a146880f0fc Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Tue, 29 Aug 2017 23:53:41 +0200 Subject: [PATCH 536/620] - Bugfixes - Make sure the login actually worked - Less output --- deploy/fritzbox.sh | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index 1290dc7a..c6a730c5 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -28,7 +28,7 @@ fritzbox_deploy() { _err "wget not found" return 1 fi - if ! exists iconv; then + if ! _exists iconv; then _err "iconv not found" return 1 fi @@ -40,23 +40,32 @@ fritzbox_deploy() { _debug _fritzbox_url "$_fritzbox_url" _debug _fritzbox_usename "$_fritzbox_username" _secure_debug _fritzbox_password "$_fritzbox_password" - if [ ! -z "$_fritzbox_username" ]; then + if [ -z "$_fritzbox_username" ]; then _err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME." return 1 fi - if [ ! -z "$_fritzbox_password" ]; then + if [ -z "$_fritzbox_password" ]; then _err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD." return 1 fi - if [ ! -z "$_fritzbox_url" ]; then + if [ -z "$_fritzbox_url" ]; then _err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL." return 1 fi - _info "Log in in to the FRITZ!Box" + _saveaccountconf DEPLOY_FRITZBOX_USERNAME "${_fritzbox_username}" + _saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}" + _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" + + _info "Log in to the FRITZ!Box" _fritzbox_challenge="$(wget -q -O - ${_fritzbox_url}/login_sid.lua | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" _fritzbox_hash="$(echo -n ${_fritzbox_challenge}-${_fritzbox_password} | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" - _fritzbox_sid="$(wget -q -O - ${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_frithbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash} | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + _fritzbox_sid="$(wget -q -O - ${_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}" -o "${_fritzbox_sid}" = "0000000000000000" ] ; then + _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." + return 1 + fi _info "Generate form POST request" _post_request="$(_mktemp)" @@ -65,6 +74,7 @@ fritzbox_deploy() { printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n${_fritzbox_sid}\r\n" >> "${_post_request}" printf -- "--${_post_boundary}\r\n" >> "${_post_request}" # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a passwort. But if they ever do, here's the place to use it! + _CERTPASSWORD_= printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n${_CERTPASSWORD_}\r\n" >> "${_post_request}" printf -- "--${_post_boundary}\r\n" >> "${_post_request}" printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" >> "${_post_request}" @@ -75,11 +85,10 @@ fritzbox_deploy() { printf -- "--${_post_boundary}--" >> "${_post_request}" _info "Upload certificate to the FRITZ!Box" - wget -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" + wget -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" | grep SSL _info "Upload successful" rm "${_post_request}" return 0 } - From d50281453d6bc704c0a647b523073f06b002ca34 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Tue, 29 Aug 2017 23:57:24 +0200 Subject: [PATCH 537/620] Add --no-check-certificate option to wget, or else the initial deployment won't work because there isn't a valid certificate installed on the router yet. --- deploy/fritzbox.sh | 6 +-- deploy/fritzbox.sh~ | 94 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 deploy/fritzbox.sh~ diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index c6a730c5..16c310bc 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -58,9 +58,9 @@ fritzbox_deploy() { _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" _info "Log in to the FRITZ!Box" - _fritzbox_challenge="$(wget -q -O - ${_fritzbox_url}/login_sid.lua | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" + _fritzbox_challenge="$(wget --no-check-certificate -q -O - ${_fritzbox_url}/login_sid.lua | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" _fritzbox_hash="$(echo -n ${_fritzbox_challenge}-${_fritzbox_password} | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" - _fritzbox_sid="$(wget -q -O - ${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_fritzbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash} | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + _fritzbox_sid="$(wget --no-check-certificate -q -O - ${_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}" -o "${_fritzbox_sid}" = "0000000000000000" ] ; then _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." @@ -85,7 +85,7 @@ fritzbox_deploy() { printf -- "--${_post_boundary}--" >> "${_post_request}" _info "Upload certificate to the FRITZ!Box" - wget -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" | grep SSL + wget --no-check-certificate -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" | grep SSL _info "Upload successful" rm "${_post_request}" diff --git a/deploy/fritzbox.sh~ b/deploy/fritzbox.sh~ new file mode 100644 index 00000000..c6a730c5 --- /dev/null +++ b/deploy/fritzbox.sh~ @@ -0,0 +1,94 @@ +#!/usr/bin/env sh + +#Here is a script to deploy cert to an AVM FRITZ!Box router. + +#returns 0 means success, otherwise error. + +#DEPLOY_FRITZBOX_USERNAME="username" +#DEPLOY_FRITZBOX_PASSWORD="password" +#DEPLOY_FRITZBOX_URL="https://fritz.box" + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +fritzbox_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if ! _exists wget; then + _err "wget not found" + return 1 + fi + if ! _exists iconv; then + _err "iconv not found" + return 1 + fi + + _fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}" + _fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}" + _fritzbox_url="${DEPLOY_FRITZBOX_URL}" + + _debug _fritzbox_url "$_fritzbox_url" + _debug _fritzbox_usename "$_fritzbox_username" + _secure_debug _fritzbox_password "$_fritzbox_password" + if [ -z "$_fritzbox_username" ]; then + _err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME." + return 1 + fi + if [ -z "$_fritzbox_password" ]; then + _err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD." + return 1 + fi + if [ -z "$_fritzbox_url" ]; then + _err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL." + return 1 + fi + + _saveaccountconf DEPLOY_FRITZBOX_USERNAME "${_fritzbox_username}" + _saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}" + _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" + + _info "Log in to the FRITZ!Box" + _fritzbox_challenge="$(wget -q -O - ${_fritzbox_url}/login_sid.lua | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" + _fritzbox_hash="$(echo -n ${_fritzbox_challenge}-${_fritzbox_password} | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" + _fritzbox_sid="$(wget -q -O - ${_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}" -o "${_fritzbox_sid}" = "0000000000000000" ] ; then + _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." + return 1 + fi + + _info "Generate form POST request" + _post_request="$(_mktemp)" + _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" + printf -- "--${_post_boundary}\r\n" >> "${_post_request}" + printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n${_fritzbox_sid}\r\n" >> "${_post_request}" + printf -- "--${_post_boundary}\r\n" >> "${_post_request}" + # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a passwort. But if they ever do, here's the place to use it! + _CERTPASSWORD_= + printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n${_CERTPASSWORD_}\r\n" >> "${_post_request}" + printf -- "--${_post_boundary}\r\n" >> "${_post_request}" + printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" >> "${_post_request}" + printf "Content-Type: application/octet-stream\r\n\r\n" >> "${_post_request}" + cat "${_ckey}" >> "${_post_request}" + cat "${_cfullchain}" >> "${_post_request}" + printf "\r\n" >> "${_post_request}" + printf -- "--${_post_boundary}--" >> "${_post_request}" + + _info "Upload certificate to the FRITZ!Box" + wget -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" | grep SSL + + _info "Upload successful" + rm "${_post_request}" + + return 0 +} From e6f81173a38c5768aae800acf058a2aea07f092e Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Tue, 29 Aug 2017 23:58:20 +0200 Subject: [PATCH 538/620] Delete auto-backup file --- deploy/fritzbox.sh~ | 94 --------------------------------------------- 1 file changed, 94 deletions(-) delete mode 100644 deploy/fritzbox.sh~ diff --git a/deploy/fritzbox.sh~ b/deploy/fritzbox.sh~ deleted file mode 100644 index c6a730c5..00000000 --- a/deploy/fritzbox.sh~ +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env sh - -#Here is a script to deploy cert to an AVM FRITZ!Box router. - -#returns 0 means success, otherwise error. - -#DEPLOY_FRITZBOX_USERNAME="username" -#DEPLOY_FRITZBOX_PASSWORD="password" -#DEPLOY_FRITZBOX_URL="https://fritz.box" - -######## Public functions ##################### - -#domain keyfile certfile cafile fullchain -fritzbox_deploy() { - _cdomain="$1" - _ckey="$2" - _ccert="$3" - _cca="$4" - _cfullchain="$5" - - _debug _cdomain "$_cdomain" - _debug _ckey "$_ckey" - _debug _ccert "$_ccert" - _debug _cca "$_cca" - _debug _cfullchain "$_cfullchain" - - if ! _exists wget; then - _err "wget not found" - return 1 - fi - if ! _exists iconv; then - _err "iconv not found" - return 1 - fi - - _fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}" - _fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}" - _fritzbox_url="${DEPLOY_FRITZBOX_URL}" - - _debug _fritzbox_url "$_fritzbox_url" - _debug _fritzbox_usename "$_fritzbox_username" - _secure_debug _fritzbox_password "$_fritzbox_password" - if [ -z "$_fritzbox_username" ]; then - _err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME." - return 1 - fi - if [ -z "$_fritzbox_password" ]; then - _err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD." - return 1 - fi - if [ -z "$_fritzbox_url" ]; then - _err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL." - return 1 - fi - - _saveaccountconf DEPLOY_FRITZBOX_USERNAME "${_fritzbox_username}" - _saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}" - _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" - - _info "Log in to the FRITZ!Box" - _fritzbox_challenge="$(wget -q -O - ${_fritzbox_url}/login_sid.lua | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" - _fritzbox_hash="$(echo -n ${_fritzbox_challenge}-${_fritzbox_password} | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" - _fritzbox_sid="$(wget -q -O - ${_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}" -o "${_fritzbox_sid}" = "0000000000000000" ] ; then - _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." - return 1 - fi - - _info "Generate form POST request" - _post_request="$(_mktemp)" - _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" - printf -- "--${_post_boundary}\r\n" >> "${_post_request}" - printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n${_fritzbox_sid}\r\n" >> "${_post_request}" - printf -- "--${_post_boundary}\r\n" >> "${_post_request}" - # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a passwort. But if they ever do, here's the place to use it! - _CERTPASSWORD_= - printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n${_CERTPASSWORD_}\r\n" >> "${_post_request}" - printf -- "--${_post_boundary}\r\n" >> "${_post_request}" - printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" >> "${_post_request}" - printf "Content-Type: application/octet-stream\r\n\r\n" >> "${_post_request}" - cat "${_ckey}" >> "${_post_request}" - cat "${_cfullchain}" >> "${_post_request}" - printf "\r\n" >> "${_post_request}" - printf -- "--${_post_boundary}--" >> "${_post_request}" - - _info "Upload certificate to the FRITZ!Box" - wget -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" | grep SSL - - _info "Upload successful" - rm "${_post_request}" - - return 0 -} From 412e4e6cf9ecbf26c4d9b9330c3dfef1ddc92e42 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Wed, 30 Aug 2017 00:24:31 +0200 Subject: [PATCH 539/620] Add acknowledgement note --- deploy/fritzbox.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index 16c310bc..804548c5 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -8,6 +8,9 @@ #DEPLOY_FRITZBOX_PASSWORD="password" #DEPLOY_FRITZBOX_URL="https://fritz.box" +# Kudos to wikrie at Github for his FRITZ!Box update script: +# https://gist.github.com/wikrie/f1d5747a714e0a34d0582981f7cb4cfb + ######## Public functions ##################### #domain keyfile certfile cafile fullchain From b6d48b7a144cefeebd3db92f8a3cabcad05139c6 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Wed, 30 Aug 2017 00:45:03 +0200 Subject: [PATCH 540/620] Update README.md for the deploy hooks. --- deploy/README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index e026cadf..d0f3d7f0 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -93,8 +93,18 @@ If you are login as root, please specify the username to deploy cert to: export DEPLOY_CPANEL_USER=username acme.sh --deploy -d example.com --deploy-hook cpanel_uapi ``` +## 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 fritz.box --deploy-hook fritzbox +``` From 103fa959cb7346d6bbade60d4009df84f1726a21 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Wed, 30 Aug 2017 00:47:31 +0200 Subject: [PATCH 541/620] Typo --- deploy/fritzbox.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index 804548c5..cea84f59 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -41,7 +41,7 @@ fritzbox_deploy() { _fritzbox_url="${DEPLOY_FRITZBOX_URL}" _debug _fritzbox_url "$_fritzbox_url" - _debug _fritzbox_usename "$_fritzbox_username" + _debug _fritzbox_username "$_fritzbox_username" _secure_debug _fritzbox_password "$_fritzbox_password" if [ -z "$_fritzbox_username" ]; then _err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME." From a3a92ff1dfc283ffc80bfd2a3cb9527295a832e7 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Thu, 31 Aug 2017 17:12:11 +0200 Subject: [PATCH 542/620] Fix formatting errors. --- deploy/fritzbox.sh | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index cea84f59..e2102eda 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -61,11 +61,11 @@ fritzbox_deploy() { _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" _info "Log in to the FRITZ!Box" - _fritzbox_challenge="$(wget --no-check-certificate -q -O - ${_fritzbox_url}/login_sid.lua | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" - _fritzbox_hash="$(echo -n ${_fritzbox_challenge}-${_fritzbox_password} | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" - _fritzbox_sid="$(wget --no-check-certificate -q -O - ${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_fritzbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash} | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + _fritzbox_challenge="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" + _fritzbox_hash="$(echo -n "${_fritzbox_challenge}-${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" + _fritzbox_sid="$(wget --no-check-certificate -q -O - "${_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}" -o "${_fritzbox_sid}" = "0000000000000000" ] ; then + if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." return 1 fi @@ -73,19 +73,24 @@ fritzbox_deploy() { _info "Generate form POST request" _post_request="$(_mktemp)" _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" - printf -- "--${_post_boundary}\r\n" >> "${_post_request}" - printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n${_fritzbox_sid}\r\n" >> "${_post_request}" - printf -- "--${_post_boundary}\r\n" >> "${_post_request}" + { + printf -- "--%s\r\n" "${_post_boundary}"; + printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}"; + printf -- "--%s\r\n""${_post_boundary}"; + } >>"${_post_request}" # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a passwort. But if they ever do, here's the place to use it! _CERTPASSWORD_= - printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n${_CERTPASSWORD_}\r\n" >> "${_post_request}" - printf -- "--${_post_boundary}\r\n" >> "${_post_request}" - printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" >> "${_post_request}" - printf "Content-Type: application/octet-stream\r\n\r\n" >> "${_post_request}" - cat "${_ckey}" >> "${_post_request}" - cat "${_cfullchain}" >> "${_post_request}" - printf "\r\n" >> "${_post_request}" - printf -- "--${_post_boundary}--" >> "${_post_request}" + { + printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}"; + printf -- "--%s\r\n" "${_post_boundary}"; + printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n"; + printf "Content-Type: application/octet-stream\r\n\r\n"; + } >>"${_post_request}" + cat "${_ckey}${_cfullchain}" >>"${_post_request}" + { + printf "\r\n"; + printf -- "--%s--" "${_post_boundary}"; + } >>"${_post_request}" _info "Upload certificate to the FRITZ!Box" wget --no-check-certificate -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" | grep SSL From 6cb5377d73c2ad6a4c9e7adfc727b191f127910b Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Thu, 31 Aug 2017 17:25:08 +0200 Subject: [PATCH 543/620] Fix bugs and more/new formatting errors. --- deploy/fritzbox.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index e2102eda..1fe28e89 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -63,7 +63,7 @@ fritzbox_deploy() { _info "Log in to the FRITZ!Box" _fritzbox_challenge="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" _fritzbox_hash="$(echo -n "${_fritzbox_challenge}-${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" - _fritzbox_sid="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua?sid=0000000000000000\&username=${_fritzbox_username}\&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + _fritzbox_sid="$(wget --no-check-certificate -q -O - "${_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 _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." @@ -74,22 +74,22 @@ fritzbox_deploy() { _post_request="$(_mktemp)" _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" { - printf -- "--%s\r\n" "${_post_boundary}"; - printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}"; - printf -- "--%s\r\n""${_post_boundary}"; + printf -- "--%s\r\n" "${_post_boundary}" + printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}" + printf -- "--%s\r\n" "${_post_boundary}" } >>"${_post_request}" # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a passwort. But if they ever do, here's the place to use it! _CERTPASSWORD_= { - printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}"; - printf -- "--%s\r\n" "${_post_boundary}"; - printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n"; - printf "Content-Type: application/octet-stream\r\n\r\n"; + printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}" + printf -- "--%s\r\n" "${_post_boundary}" + printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" + printf "Content-Type: application/octet-stream\r\n\r\n" } >>"${_post_request}" - cat "${_ckey}${_cfullchain}" >>"${_post_request}" + cat "${_ckey}" "${_cfullchain}" >>"${_post_request}" { - printf "\r\n"; - printf -- "--%s--" "${_post_boundary}"; + printf "\r\n" + printf -- "--%s--" "${_post_boundary}" } >>"${_post_request}" _info "Upload certificate to the FRITZ!Box" From 3794b5cb5846cc9713979027d68fc930211ec86e Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 1 Sep 2017 23:01:37 +0800 Subject: [PATCH 544/620] fix changes for :https://community.letsencrypt.org/t/acme-sh-standalone-fails-multiple-validation-requests-staging-multi-va/41249/8 use socat instead of nc. --- acme.sh | 79 +++++++++++++-------------------------------------------- 1 file changed, 17 insertions(+), 62 deletions(-) diff --git a/acme.sh b/acme.sh index cd2f981c..c7f8eddd 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.3 +VER=2.7.4 PROJECT_NAME="acme.sh" @@ -164,11 +164,11 @@ _dlg_versions() { echo "nginx doesn't exists." fi - echo "nc:" - if _exists "nc"; then - nc -h 2>&1 + echo "socat:" + if _exists "socat"; then + socat -h 2>&1 else - _debug "nc doesn't exists." + _debug "socat doesn't exists." fi } @@ -1967,68 +1967,22 @@ _startserver() { _debug "ncaddr" "$ncaddr" _debug "startserver: $$" - nchelp="$(nc -h 2>&1)" _debug Le_HTTPPort "$Le_HTTPPort" _debug Le_Listen_V4 "$Le_Listen_V4" _debug Le_Listen_V6 "$Le_Listen_V6" - _NC="nc" + _NC="socat" if [ "$Le_Listen_V4" ]; then _NC="$_NC -4" elif [ "$Le_Listen_V6" ]; then _NC="$_NC -6" fi - if [ "$Le_Listen_V4$Le_Listen_V6$ncaddr" ]; then - if ! _contains "$nchelp" "-4"; then - _err "The nc doesn't support '-4', '-6' or local-address, please install 'netcat-openbsd' and try again." - _err "See $(__green $_PREPARE_LINK)" - return 1 - fi - fi - - if echo "$nchelp" | grep "\-q[ ,]" >/dev/null; then - _NC="$_NC -q 1 -l $ncaddr" - else - if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null; then - _NC="$_NC -c -l $ncaddr" - elif echo "$nchelp" | grep "\-N" | grep "Shutdown the network socket after EOF on stdin" >/dev/null; then - _NC="$_NC -N -l $ncaddr" - else - _NC="$_NC -l $ncaddr" - fi - fi - _debug "_NC" "$_NC" - - #for centos ncat - if _contains "$nchelp" "nmap.org"; then - _debug "Using ncat: nmap.org" - if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2"; then - _exec_err - return 1 - fi - if [ "$DEBUG" ]; then - _exec_err - fi - return - fi - - # while true ; do - if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC -p \"$Le_HTTPPort\" >&2"; then - _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2" - fi - - if [ "$?" != "0" ]; then - _err "nc listen error." - _exec_err - exit 1 - fi - if [ "$DEBUG" ]; then - _exec_err - fi - # done + #todo listen address + socat TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & + serverproc="$!" } _stopserver() { @@ -2038,6 +1992,8 @@ _stopserver() { return fi + kill $pid + _debug2 "Le_HTTPPort" "$Le_HTTPPort" if [ "$Le_HTTPPort" ]; then if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then @@ -2943,8 +2899,8 @@ _on_before_issue() { fi if _hasfield "$_chk_web_roots" "$NO_VALUE"; then - if ! _exists "nc"; then - _err "Please install netcat(nc) tools first." + if ! _exists "socat"; then + _err "Please install socat tools first." return 1 fi fi @@ -3665,13 +3621,12 @@ issue() { _info "Standalone mode server" _ncaddr="$(_getfield "$_local_addr" "$_ncIndex")" _ncIndex="$(_math $_ncIndex + 1)" - _startserver "$keyauthorization" "$_ncaddr" & + _startserver "$keyauthorization" "$_ncaddr" if [ "$?" != "0" ]; then _clearup _on_issue_err "$_post_hook" "$vlist" return 1 fi - serverproc="$!" sleep 1 _debug serverproc "$serverproc" elif [ "$_currentRoot" = "$MODE_STATELESS" ]; then @@ -4788,9 +4743,9 @@ _precheck() { return 1 fi - if ! _exists "nc"; then - _err "It is recommended to install nc first, try to install 'nc' or 'netcat'." - _err "We use nc for standalone server if you use standalone mode." + if ! _exists "socat"; then + _err "It is recommended to install socat first." + _err "We use socat for standalone server if you use standalone mode." _err "If you don't use standalone mode, just ignore this warning." fi From 443a5ca0c2d0af8e11f720f3acbb04ee628a001b Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 1 Sep 2017 23:44:52 +0800 Subject: [PATCH 545/620] socat tls mode --- acme.sh | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/acme.sh b/acme.sh index c7f8eddd..84ae7e93 100755 --- a/acme.sh +++ b/acme.sh @@ -1994,25 +1994,6 @@ _stopserver() { kill $pid - _debug2 "Le_HTTPPort" "$Le_HTTPPort" - if [ "$Le_HTTPPort" ]; then - if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then - _get "http://localhost:$Le_HTTPPort" "" 1 - else - _get "http://localhost:$Le_HTTPPort" "" 1 >/dev/null 2>&1 - fi - fi - - _debug2 "Le_TLSPort" "$Le_TLSPort" - if [ "$Le_TLSPort" ]; then - if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then - _get "https://localhost:$Le_TLSPort" "" 1 - _get "https://localhost:$Le_TLSPort" "" 1 - else - _get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1 - _get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1 - fi - fi } # sleep sec @@ -2067,12 +2048,7 @@ _starttlsserver() { return 1 fi - __S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -cert $TLS_CERT -key $TLS_KEY " - if [ "$opaddr" ]; then - __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" - else - __S_OPENSSL="$__S_OPENSSL -accept $port" - fi + __S_OPENSSL="socat" _debug Le_Listen_V4 "$Le_Listen_V4" _debug Le_Listen_V6 "$Le_Listen_V6" @@ -2083,12 +2059,9 @@ _starttlsserver() { fi _debug "$__S_OPENSSL" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - (printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL -tlsextdebug) & - else - (printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL >/dev/null 2>&1) & - fi + #todo listen address + $__S_OPENSSL openssl-listen:$port,cert=$TLS_CERT,key=$TLS_KEY,verify=0,reuseaddr,fork SYSTEM:"echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & serverproc="$!" sleep 1 _debug serverproc "$serverproc" From 7b8ddfdd96d5edd6992335a1f289b845ab9403d2 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 2 Sep 2017 08:59:30 +0800 Subject: [PATCH 546/620] use socat --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2ba02b9c..1378e947 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ install: - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then brew update && brew install openssl; brew info openssl; + brew info socat; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl; @@ -30,6 +31,7 @@ install: openssl version 2>&1 || true; $ACME_OPENSSL_BIN version 2>&1 || true; export PATH="$_old_path"; + else sudo apt-get install socat; fi script: From cc6610edc2fe1c4d19aed233ac5449b2124de4ea Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 2 Sep 2017 17:32:40 +0800 Subject: [PATCH 547/620] add socat --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1378e947..b45cc464 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,9 +18,8 @@ addons: install: - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then - brew update && brew install openssl; + brew update && brew install openssl socat; brew info openssl; - brew info socat; ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl; From f9cdfd3e5baf89eb84f04a5a912223e2c57c01bb Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 2 Sep 2017 18:58:07 +0800 Subject: [PATCH 548/620] fix for behind proxy --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 84ae7e93..07617c40 100755 --- a/acme.sh +++ b/acme.sh @@ -1981,7 +1981,7 @@ _startserver() { _debug "_NC" "$_NC" #todo listen address - socat TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & + socat TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & serverproc="$!" } @@ -2061,7 +2061,7 @@ _starttlsserver() { _debug "$__S_OPENSSL" #todo listen address - $__S_OPENSSL openssl-listen:$port,cert=$TLS_CERT,key=$TLS_KEY,verify=0,reuseaddr,fork SYSTEM:"echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & + $__S_OPENSSL openssl-listen:$port,cert=$TLS_CERT,key=$TLS_KEY,verify=0,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & serverproc="$!" sleep 1 _debug serverproc "$serverproc" From 6104680caa1c1542b5c2291b8392f5b67b061717 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 2 Sep 2017 20:46:04 +0800 Subject: [PATCH 549/620] fix https://github.com/Neilpang/acme.sh/issues/999 --- acme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 07617c40..45287eef 100755 --- a/acme.sh +++ b/acme.sh @@ -3934,7 +3934,10 @@ issue() { Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400) _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" - _on_issue_success "$_post_hook" "$_renew_hook" + if ! _on_issue_success "$_post_hook" "$_renew_hook"; then + _err "Call hook error." + return 1 + fi if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then _savedomainconf "Le_RealCertPath" "$_real_cert" From 4356eefbb10d519cdbd6d44a52b757e3df348075 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 3 Sep 2017 08:42:44 +0800 Subject: [PATCH 550/620] fix https://github.com/Neilpang/acme.sh/issues/1005#event-1232471561 --- acme.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 45287eef..f6447f73 100755 --- a/acme.sh +++ b/acme.sh @@ -4821,9 +4821,11 @@ install() { _debug "Skip install cron job" fi - if ! _precheck "$_nocron"; then - _err "Pre-check failed, can not install." - return 1 + if [ "$IN_CRON" != "1" ]; then + if ! _precheck "$_nocron"; then + _err "Pre-check failed, can not install." + return 1 + fi fi if [ -z "$_c_home" ] && [ "$LE_CONFIG_HOME" != "$LE_WORKING_DIR" ]; then @@ -4876,7 +4878,9 @@ install() { _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY" - _installalias "$_c_home" + if [ "$IN_CRON" != "1" ]; then + _installalias "$_c_home" + fi for subf in $_SUB_FOLDERS; do if [ -d "$subf" ]; then From c73fdd402243071d01a23eae7ae17088b5914d7d Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 3 Sep 2017 08:45:58 +0800 Subject: [PATCH 551/620] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index f6447f73..e482b87b 100755 --- a/acme.sh +++ b/acme.sh @@ -4970,7 +4970,7 @@ _uninstallalias() { } cron() { - IN_CRON=1 + export IN_CRON=1 _initpath _info "$(__green "===Starting cron===")" if [ "$AUTO_UPGRADE" = "1" ]; then From e52304edb47b974c905e88bc41b7124705f514e6 Mon Sep 17 00:00:00 2001 From: Santeri Date: Sun, 3 Sep 2017 13:35:20 +0400 Subject: [PATCH 552/620] cpanel_uapi tried to make it a bit less confusing --- deploy/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index e026cadf..62a3fb6f 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -6,6 +6,8 @@ Here are the scripts to deploy the certs/key to the server/services. ## 1. Deploy the certs to your cpanel host. +If you want to deploy using cpanel UAPI see 7. + (cpanel deploy hook is not finished yet, this is just an example.) @@ -81,14 +83,13 @@ acme.sh --deploy -d ftp.example.com --deploy-hook exim4 acme.sh --deploy -d ftp.example.com --deploy-hook keychain ``` -## 7. Deploy to cpanel host. +## 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 ``` - -If you are login as root, please specify the username to deploy cert to: - +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 From a098167bdbd145ff3d522b33c4d18f99e8ff09ec Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Mon, 4 Sep 2017 14:07:10 +0200 Subject: [PATCH 553/620] Fix more formatting errors --- deploy/fritzbox.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index 1fe28e89..c86b44ad 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -62,7 +62,7 @@ fritzbox_deploy() { _info "Log in to the FRITZ!Box" _fritzbox_challenge="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" - _fritzbox_hash="$(echo -n "${_fritzbox_challenge}-${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" + _fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')" _fritzbox_sid="$(wget --no-check-certificate -q -O - "${_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 @@ -73,14 +73,12 @@ fritzbox_deploy() { _info "Generate form POST request" _post_request="$(_mktemp)" _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" + # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a password. But if they ever do, here's the place to use it! + _CERTPASSWORD_= { printf -- "--%s\r\n" "${_post_boundary}" printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}" printf -- "--%s\r\n" "${_post_boundary}" - } >>"${_post_request}" - # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a passwort. But if they ever do, here's the place to use it! - _CERTPASSWORD_= - { printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}" printf -- "--%s\r\n" "${_post_boundary}" printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" From bd8b1a2501a867a373772398b3687ac47341f0f5 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Mon, 4 Sep 2017 14:27:22 +0200 Subject: [PATCH 554/620] Don't use wget directly, but instead use _get and _post. --- deploy/fritzbox.sh | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index c86b44ad..e7d01a8b 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -27,10 +27,6 @@ fritzbox_deploy() { _debug _cca "$_cca" _debug _cfullchain "$_cfullchain" - if ! _exists wget; then - _err "wget not found" - return 1 - fi if ! _exists iconv; then _err "iconv not found" return 1 @@ -60,10 +56,13 @@ fritzbox_deploy() { _saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}" _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" + # Do not check for a valid SSL certificate, because initially the cert is not valid, so it could not install the LE generated certificate + export HTTPS_INSECURE=1 + _info "Log in to the FRITZ!Box" - _fritzbox_challenge="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" + _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}')" - _fritzbox_sid="$(wget --no-check-certificate -q -O - "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + _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 _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." @@ -91,10 +90,17 @@ fritzbox_deploy() { } >>"${_post_request}" _info "Upload certificate to the FRITZ!Box" - wget --no-check-certificate -q -O - "${_fritzbox_url}/cgi-bin/firmwarecfg" --header="Content-type: multipart/form-data boundary=${_post_boundary}" --post-file "${_post_request}" | grep SSL - _info "Upload successful" + export _H1="Content-type: multipart/form-data boundary=${_post_boundary}" + _post "$(cat ${_post_request})" "${_fritzbox_url}/cgi-bin/firmwarecfg" | grep SSL + + retval=$? + if [ $retval = 0 ] ; then + _info "Upload successful" + else + _err "Upload failed" + fi rm "${_post_request}" - return 0 + return $retval } From 8ee5ede834f2493b9d0e3af9a251ccfbaf4156ec Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Mon, 4 Sep 2017 14:30:40 +0200 Subject: [PATCH 555/620] Fix more formatting errors --- deploy/fritzbox.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index e7d01a8b..a6f6684c 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -92,10 +92,10 @@ fritzbox_deploy() { _info "Upload certificate to the FRITZ!Box" export _H1="Content-type: multipart/form-data boundary=${_post_boundary}" - _post "$(cat ${_post_request})" "${_fritzbox_url}/cgi-bin/firmwarecfg" | grep SSL + _post "$(cat "${_post_request}")" "${_fritzbox_url}/cgi-bin/firmwarecfg" | grep SSL retval=$? - if [ $retval = 0 ] ; then + if [ $retval = 0 ]; then _info "Upload successful" else _err "Upload failed" From 72e1eb88d969dfb26935b1c8070db7685105d6b1 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Mon, 4 Sep 2017 14:40:28 +0200 Subject: [PATCH 556/620] Don't use individual redirects, but do it all in one block. --- deploy/fritzbox.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index a6f6684c..dbff3680 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -82,9 +82,7 @@ fritzbox_deploy() { printf -- "--%s\r\n" "${_post_boundary}" printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" printf "Content-Type: application/octet-stream\r\n\r\n" - } >>"${_post_request}" - cat "${_ckey}" "${_cfullchain}" >>"${_post_request}" - { + cat "${_ckey}" "${_cfullchain}" printf "\r\n" printf -- "--%s--" "${_post_boundary}" } >>"${_post_request}" From 1e30718df63555700444226ef056f132f8620a1c Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Mon, 4 Sep 2017 14:48:27 +0200 Subject: [PATCH 557/620] Try and work around shellcheck error SC2039: In POSIX sh, printf -%s-- is undefined. --- deploy/fritzbox.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/deploy/fritzbox.sh b/deploy/fritzbox.sh index dbff3680..943b198d 100644 --- a/deploy/fritzbox.sh +++ b/deploy/fritzbox.sh @@ -75,16 +75,20 @@ fritzbox_deploy() { # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a password. But if they ever do, here's the place to use it! _CERTPASSWORD_= { - printf -- "--%s\r\n" "${_post_boundary}" + printf -- "--" + printf -- "%s\r\n" "${_post_boundary}" printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}" - printf -- "--%s\r\n" "${_post_boundary}" + printf -- "--" + printf -- "%s\r\n" "${_post_boundary}" printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}" - printf -- "--%s\r\n" "${_post_boundary}" + printf -- "--" + printf -- "%s\r\n" "${_post_boundary}" printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" printf "Content-Type: application/octet-stream\r\n\r\n" cat "${_ckey}" "${_cfullchain}" printf "\r\n" - printf -- "--%s--" "${_post_boundary}" + printf -- "--" + printf -- "%s--" "${_post_boundary}" } >>"${_post_request}" _info "Upload certificate to the FRITZ!Box" From 8148bfeacf43a311551c00473f39c514e5f50d52 Mon Sep 17 00:00:00 2001 From: neilpang Date: Tue, 5 Sep 2017 20:32:14 +0800 Subject: [PATCH 558/620] fix https://github.com/Neilpang/acme.sh/issues/998 --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index e482b87b..d9855651 100755 --- a/acme.sh +++ b/acme.sh @@ -1814,7 +1814,12 @@ _send_signed_request() { _CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" - if _contains "$response" "JWS has invalid anti-replay nonce"; then + _body="$response" + if [ "$needbase64" ]; then + _body="$(echo "$_body" | _dbase64)" + fi + _debug3 _body "$_body" + if _contains "$_body" "JWS has invalid anti-replay nonce"; then _info "It seems the CA server is busy now, let's wait and retry." _request_retry_times=$(_math "$_request_retry_times" + 1) _sleep 5 From f81d4033fa0e85f4a4cb789e250bb52d3a282e5f Mon Sep 17 00:00:00 2001 From: Santeri Kannisto Date: Tue, 5 Sep 2017 17:37:48 +0400 Subject: [PATCH 559/620] One cert per domain Deploy works only for the first domain --- deploy/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/README.md b/deploy/README.md index 62a3fb6f..48caea6f 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -94,6 +94,7 @@ DEPLOY_CPANEL_USER is required only if you run the script as root and it should 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 only one certificate per domain. From a9726fde1948c7404e8873e9b6264785081b025a Mon Sep 17 00:00:00 2001 From: Santeri Kannisto Date: Tue, 5 Sep 2017 17:42:17 +0400 Subject: [PATCH 560/620] 1 cert per domain for cpanel_uapi --- deploy/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index 48caea6f..c80a567e 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -94,7 +94,7 @@ DEPLOY_CPANEL_USER is required only if you run the script as root and it should 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 only one certificate per domain. +Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue a separete certificate for each domain. From 3eeb090578a371eb5e5ce507adb27a6cf1676ac8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 6 Sep 2017 20:50:31 +0800 Subject: [PATCH 561/620] fix tls mode back to use openssl --- acme.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index d9855651..83c06fa5 100755 --- a/acme.sh +++ b/acme.sh @@ -2053,7 +2053,12 @@ _starttlsserver() { return 1 fi - __S_OPENSSL="socat" + __S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -www -cert $TLS_CERT -key $TLS_KEY " + if [ "$opaddr" ]; then + __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" + else + __S_OPENSSL="$__S_OPENSSL -accept $port" + fi _debug Le_Listen_V4 "$Le_Listen_V4" _debug Le_Listen_V6 "$Le_Listen_V6" @@ -2064,9 +2069,12 @@ _starttlsserver() { fi _debug "$__S_OPENSSL" + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + $__S_OPENSSL -tlsextdebug & + else + $__S_OPENSSL >/dev/null 2>&1 & + fi - #todo listen address - $__S_OPENSSL openssl-listen:$port,cert=$TLS_CERT,key=$TLS_KEY,verify=0,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & serverproc="$!" sleep 1 _debug serverproc "$serverproc" From 53273a15bf54d2b3c48e8351c592f42ee1e49dab Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 6 Sep 2017 21:18:02 +0800 Subject: [PATCH 562/620] use socat for tls mode --- acme.sh | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/acme.sh b/acme.sh index 83c06fa5..d9855651 100755 --- a/acme.sh +++ b/acme.sh @@ -2053,12 +2053,7 @@ _starttlsserver() { return 1 fi - __S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -www -cert $TLS_CERT -key $TLS_KEY " - if [ "$opaddr" ]; then - __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" - else - __S_OPENSSL="$__S_OPENSSL -accept $port" - fi + __S_OPENSSL="socat" _debug Le_Listen_V4 "$Le_Listen_V4" _debug Le_Listen_V6 "$Le_Listen_V6" @@ -2069,12 +2064,9 @@ _starttlsserver() { fi _debug "$__S_OPENSSL" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - $__S_OPENSSL -tlsextdebug & - else - $__S_OPENSSL >/dev/null 2>&1 & - fi + #todo listen address + $__S_OPENSSL openssl-listen:$port,cert=$TLS_CERT,key=$TLS_KEY,verify=0,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & serverproc="$!" sleep 1 _debug serverproc "$serverproc" From 856811bd2e23279fcc44efed041c65e011253eb7 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Wed, 6 Sep 2017 17:04:40 +0000 Subject: [PATCH 563/620] Use stable gandi API url The gandi api has changed its url for a more stable one. Although https://dns.beta.gandi.net will continue to work for the foreseable future, this commits updates the url to new official one. --- dnsapi/dns_gandi_livedns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh index 82ed599c..7a21aba6 100755 --- a/dnsapi/dns_gandi_livedns.sh +++ b/dnsapi/dns_gandi_livedns.sh @@ -11,7 +11,7 @@ # ######## Public functions ##################### -GANDI_LIVEDNS_API="https://dns.beta.gandi.net/api/v5" +GANDI_LIVEDNS_API="https://dns.api.gandi.net/api/v5" #Usage: dns_gandi_livedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_gandi_livedns_add() { From a6b399286e4dcd387c5193589358d066174d51eb Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 9 Sep 2017 14:15:11 +0800 Subject: [PATCH 564/620] add socat --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 7ca042ea..e85098e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ RUN apk update -f \ && apk --no-cache add -f \ openssl \ curl \ - netcat-openbsd \ + socat \ && rm -rf /var/cache/apk/* ENV LE_CONFIG_HOME /acme.sh From 36309e6dbc5b074b108c268bb2a652689aae379d Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 11 Sep 2017 21:28:37 +0800 Subject: [PATCH 565/620] minor, fix debug info --- acme.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index d9855651..b1a7f68a 100755 --- a/acme.sh +++ b/acme.sh @@ -1817,8 +1817,9 @@ _send_signed_request() { _body="$response" if [ "$needbase64" ]; then _body="$(echo "$_body" | _dbase64)" + _debug2 _body "$_body" fi - _debug3 _body "$_body" + if _contains "$_body" "JWS has invalid anti-replay nonce"; then _info "It seems the CA server is busy now, let's wait and retry." _request_retry_times=$(_math "$_request_retry_times" + 1) From 95949b6519b4b7e8de5f8dc83ef900d558caa331 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 11 Sep 2017 21:40:56 +0800 Subject: [PATCH 566/620] minor --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index b1a7f68a..e7746931 100755 --- a/acme.sh +++ b/acme.sh @@ -1987,7 +1987,7 @@ _startserver() { _debug "_NC" "$_NC" #todo listen address - socat TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & + $_NC TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & serverproc="$!" } From 2fc0225bc98da5e0a7221c12ea13b20c9cf26ec2 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Tue, 12 Sep 2017 11:35:21 +0200 Subject: [PATCH 567/620] Make command line example consistent with env variable example. --- deploy/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index f76c667a..af6fc5f3 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -108,6 +108,6 @@ $ 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 fritz.box --deploy-hook fritzbox +acme.sh --deploy -d fritzbox.example.com --deploy-hook fritzbox ``` From 270ce87582e8749b629033c2448bccf313aeb365 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 23 Sep 2017 22:12:17 +0800 Subject: [PATCH 568/620] add debug info --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index e7746931..0f2a436d 100755 --- a/acme.sh +++ b/acme.sh @@ -2241,6 +2241,7 @@ _initpath() { fi fi + _debug2 ACME_DIRECTORY "$ACME_DIRECTORY" _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)" _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" From acf117584bb92c3c5e06774ef1c5b5fd7c4582cc Mon Sep 17 00:00:00 2001 From: Santeri Kannisto Date: Tue, 26 Sep 2017 07:04:30 +0400 Subject: [PATCH 569/620] #1042 Apparently UAPI does not return any error code, just JSON output that has a string "status: 0" whenever the command fails. --- 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 2ba112c4..4563b9c4 100644 --- a/deploy/cpanel_uapi.sh +++ b/deploy/cpanel_uapi.sh @@ -51,8 +51,8 @@ cpanel_uapi_deploy() { else _response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") fi - - if [ $? -ne 0 ]; then + error_response="status: 0" + if test "${_response#*$error_response}" != "$_response"; then _err "Error in deploying certificate:" _err "$_response" return 1 From 5261162fdfbc4cfe458267e822a9f89a4bea7f16 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 26 Sep 2017 19:43:06 +0400 Subject: [PATCH 570/620] Remove stray single-quote Get rid of a single stray erroneous single-quote that is breaking socat when using standalone mode. --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 0f2a436d..3e63282d 100755 --- a/acme.sh +++ b/acme.sh @@ -1987,7 +1987,7 @@ _startserver() { _debug "_NC" "$_NC" #todo listen address - $_NC TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & + $_NC TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK; echo ; echo $content; echo;" & serverproc="$!" } From 754a4a7c8bef3fcaa384be159e1744cdae0399bc Mon Sep 17 00:00:00 2001 From: sahsanu Date: Sat, 30 Sep 2017 20:12:53 +0200 Subject: [PATCH 571/620] Update dns_cloudns.sh Added code to save CLOUDNS_AUTH_ID and CLOUDNS_AUTH_PASSWORD on account.conf file so the id and password for cloudns can be reused. --- dnsapi/dns_cloudns.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index f48a8052..14403a7d 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -96,6 +96,16 @@ _dns_cloudns_init_check() { return 0 fi + CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}" + CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}" + if [ -z "$CLOUDNS_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then + CLOUDNS_AUTH_ID="" + CLOUDNS_AUTH_PASSWORD="" + _err "You don't specify cloudns api id and password yet." + _err "Please create you id and password and try again." + return 1 + fi + if [ -z "$CLOUDNS_AUTH_ID" ]; then _err "CLOUDNS_AUTH_ID is not configured" return 1 @@ -113,8 +123,12 @@ _dns_cloudns_init_check() { return 1 fi + #save the api id and password to the account conf file. + _saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" + _saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" + CLOUDNS_INIT_CHECK_COMPLETED=1 - + return 0 } From 6c7da215e7d364fb9d9af3274397c947269b966e Mon Sep 17 00:00:00 2001 From: sahsanu Date: Sun, 1 Oct 2017 10:06:38 +0200 Subject: [PATCH 572/620] Update dns_cloudns.sh --- dnsapi/dns_cloudns.sh | 272 ++++++++++++++++++++---------------------- 1 file changed, 129 insertions(+), 143 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 14403a7d..2ad77ca0 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -11,174 +11,160 @@ CLOUDNS_API="https://api.cloudns.net" #Usage: dns_cloudns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_cloudns_add() { - _info "Using cloudns" - - if ! _dns_cloudns_init_check; then - return 1 - fi - - zone="$(_dns_cloudns_get_zone_name "$1")" - if [ -z "$zone" ]; then - _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." - return 1 - fi - - host="$(echo "$1" | sed "s/\.$zone\$//")" - record=$2 - record_id=$(_dns_cloudns_get_record_id "$zone" "$host") - - _debug zone "$zone" - _debug host "$host" - _debug record "$record" - _debug record_id "$record_id" - - if [ -z "$record_id" ]; then - _info "Adding the TXT record for $1" - _dns_cloudns_http_api_call "dns/add-record.json" "domain-name=$zone&record-type=TXT&host=$host&record=$record&ttl=60" - if ! _contains "$response" "\"status\":\"Success\""; then - _err "Record cannot be added." - return 1 - fi - _info "Added." - else - _info "Updating the TXT record for $1" - _dns_cloudns_http_api_call "dns/mod-record.json" "domain-name=$zone&record-id=$record_id&record-type=TXT&host=$host&record=$record&ttl=60" - if ! _contains "$response" "\"status\":\"Success\""; then - _err "The TXT record for $1 cannot be updated." - return 1 - fi - _info "Updated." - fi - - return 0 + _info "Using cloudns" + + if ! _dns_cloudns_init_check; then + return 1 + fi + + zone="$(_dns_cloudns_get_zone_name "$1")" + if [ -z "$zone" ]; then + _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." + return 1 + fi + + host="$(echo "$1" | sed "s/\.$zone\$//")" + record=$2 + record_id=$(_dns_cloudns_get_record_id "$zone" "$host") + + _debug zone "$zone" + _debug host "$host" + _debug record "$record" + _debug record_id "$record_id" + + if [ -z "$record_id" ]; then + _info "Adding the TXT record for $1" + _dns_cloudns_http_api_call "dns/add-record.json" "domain-name=$zone&record-type=TXT&host=$host&record=$record&ttl=60" + if ! _contains "$response" "\"status\":\"Success\""; then + _err "Record cannot be added." + return 1 + fi + _info "Added." + else + _info "Updating the TXT record for $1" + _dns_cloudns_http_api_call "dns/mod-record.json" "domain-name=$zone&record-id=$record_id&record-type=TXT&host=$host&record=$record&ttl=60" + if ! _contains "$response" "\"status\":\"Success\""; then + _err "The TXT record for $1 cannot be updated." + return 1 + fi + _info "Updated." + fi + + return 0 } #Usage: dns_cloudns_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_cloudns_rm() { - _info "Using cloudns" - - if ! _dns_cloudns_init_check; then - return 1 - fi - - if [ -z "$zone" ]; then - zone="$(_dns_cloudns_get_zone_name "$1")" - if [ -z "$zone" ]; then - _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." - return 1 - fi - fi - - host="$(echo "$1" | sed "s/\.$zone\$//")" - record=$2 - record_id=$(_dns_cloudns_get_record_id "$zone" "$host") - - _debug zone "$zone" - _debug host "$host" - _debug record "$record" - _debug record_id "$record_id" - - if [ ! -z "$record_id" ]; then - _info "Deleting the TXT record for $1" - _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=$record_id" - if ! _contains "$response" "\"status\":\"Success\""; then - _err "The TXT record for $1 cannot be deleted." - return 1 - fi - _info "Deleted." - fi - return 0 + _info "Using cloudns" + + if ! _dns_cloudns_init_check; then + return 1 + fi + + if [ -z "$zone" ]; then + zone="$(_dns_cloudns_get_zone_name "$1")" + if [ -z "$zone" ]; then + _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." + return 1 + fi + fi + + host="$(echo "$1" | sed "s/\.$zone\$//")" + record=$2 + record_id=$(_dns_cloudns_get_record_id "$zone" "$host") + + _debug zone "$zone" + _debug host "$host" + _debug record "$record" + _debug record_id "$record_id" + + if [ ! -z "$record_id" ]; then + _info "Deleting the TXT record for $1" + _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=$record_id" + if ! _contains "$response" "\"status\":\"Success\""; then + _err "The TXT record for $1 cannot be deleted." + return 1 + fi + _info "Deleted." + fi + return 0 } #################### Private functions below ################################## _dns_cloudns_init_check() { - if [ ! -z "$CLOUDNS_INIT_CHECK_COMPLETED" ]; then - return 0 - fi - - CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}" - CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}" - if [ -z "$CLOUDNS_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then - CLOUDNS_AUTH_ID="" - CLOUDNS_AUTH_PASSWORD="" - _err "You don't specify cloudns api id and password yet." - _err "Please create you id and password and try again." - return 1 - fi - - if [ -z "$CLOUDNS_AUTH_ID" ]; then - _err "CLOUDNS_AUTH_ID is not configured" - return 1 - fi - - if [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then - _err "CLOUDNS_AUTH_PASSWORD is not configured" - return 1 - fi - - _dns_cloudns_http_api_call "dns/login.json" "" - - if ! _contains "$response" "\"status\":\"Success\""; then - _err "Invalid CLOUDNS_AUTH_ID or CLOUDNS_AUTH_PASSWORD. Please check your login credentials." - return 1 - fi - - #save the api id and password to the account conf file. - _saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" - _saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" - - CLOUDNS_INIT_CHECK_COMPLETED=1 - - return 0 + if [ ! -z "$CLOUDNS_INIT_CHECK_COMPLETED" ]; then + return 0 + fi + + if [ -z "$CLOUDNS_AUTH_ID" ]; then + _err "CLOUDNS_AUTH_ID is not configured" + return 1 + fi + + if [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then + _err "CLOUDNS_AUTH_PASSWORD is not configured" + return 1 + fi + + _dns_cloudns_http_api_call "dns/login.json" "" + + if ! _contains "$response" "\"status\":\"Success\""; then + _err "Invalid CLOUDNS_AUTH_ID or CLOUDNS_AUTH_PASSWORD. Please check your login credentials." + return 1 + fi + + CLOUDNS_INIT_CHECK_COMPLETED=1 + + return 0 } _dns_cloudns_get_zone_name() { - i=2 - while true; do - zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) + i=2 + while true; do + zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) - if [ -z "$zoneForCheck" ]; then - return 1 - fi + if [ -z "$zoneForCheck" ]; then + return 1 + fi - _debug zoneForCheck "$zoneForCheck" + _debug zoneForCheck "$zoneForCheck" - _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" + _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" - if ! _contains "$response" "\"status\":\"Failed\""; then - echo "$zoneForCheck" - return 0 - fi + if ! _contains "$response" "\"status\":\"Failed\""; then + echo "$zoneForCheck" + return 0 + fi - i=$(_math "$i" + 1) - done - return 1 + i=$(_math "$i" + 1) + done + return 1 } _dns_cloudns_get_record_id() { - _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" - if _contains "$response" "\"id\":"; then - echo "$response" | cut -d '"' -f 2 - return 0 - fi - return 1 + _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" + if _contains "$response" "\"id\":"; then + echo "$response" | cut -d '"' -f 2 + return 0 + fi + return 1 } _dns_cloudns_http_api_call() { - method=$1 + method=$1 - _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" - _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" + _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" + _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" - if [ -z "$2" ]; then - data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD" - else - data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" - fi + if [ -z "$2" ]; then + data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD" + else + data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" + fi - response="$(_get "$CLOUDNS_API/$method?$data")" + response="$(_get "$CLOUDNS_API/$method?$data")" - _debug2 response "$response" + _debug2 response "$response" - return 0 + return 0 } From c73c33f94c4d5731ef1d9bee92a33ab71dea1f92 Mon Sep 17 00:00:00 2001 From: sahsanu Date: Sun, 1 Oct 2017 10:31:38 +0200 Subject: [PATCH 573/620] Update dns_cloudns.sh --- dnsapi/dns_cloudns.sh | 272 ++++++++++++++++++++++-------------------- 1 file changed, 143 insertions(+), 129 deletions(-) diff --git a/dnsapi/dns_cloudns.sh b/dnsapi/dns_cloudns.sh index 2ad77ca0..b1861b24 100755 --- a/dnsapi/dns_cloudns.sh +++ b/dnsapi/dns_cloudns.sh @@ -11,160 +11,174 @@ CLOUDNS_API="https://api.cloudns.net" #Usage: dns_cloudns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_cloudns_add() { - _info "Using cloudns" - - if ! _dns_cloudns_init_check; then - return 1 - fi - - zone="$(_dns_cloudns_get_zone_name "$1")" - if [ -z "$zone" ]; then - _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." - return 1 - fi - - host="$(echo "$1" | sed "s/\.$zone\$//")" - record=$2 - record_id=$(_dns_cloudns_get_record_id "$zone" "$host") - - _debug zone "$zone" - _debug host "$host" - _debug record "$record" - _debug record_id "$record_id" - - if [ -z "$record_id" ]; then - _info "Adding the TXT record for $1" - _dns_cloudns_http_api_call "dns/add-record.json" "domain-name=$zone&record-type=TXT&host=$host&record=$record&ttl=60" - if ! _contains "$response" "\"status\":\"Success\""; then - _err "Record cannot be added." - return 1 - fi - _info "Added." - else - _info "Updating the TXT record for $1" - _dns_cloudns_http_api_call "dns/mod-record.json" "domain-name=$zone&record-id=$record_id&record-type=TXT&host=$host&record=$record&ttl=60" - if ! _contains "$response" "\"status\":\"Success\""; then - _err "The TXT record for $1 cannot be updated." - return 1 - fi - _info "Updated." - fi - - return 0 + _info "Using cloudns" + + if ! _dns_cloudns_init_check; then + return 1 + fi + + zone="$(_dns_cloudns_get_zone_name "$1")" + if [ -z "$zone" ]; then + _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." + return 1 + fi + + host="$(echo "$1" | sed "s/\.$zone\$//")" + record=$2 + record_id=$(_dns_cloudns_get_record_id "$zone" "$host") + + _debug zone "$zone" + _debug host "$host" + _debug record "$record" + _debug record_id "$record_id" + + if [ -z "$record_id" ]; then + _info "Adding the TXT record for $1" + _dns_cloudns_http_api_call "dns/add-record.json" "domain-name=$zone&record-type=TXT&host=$host&record=$record&ttl=60" + if ! _contains "$response" "\"status\":\"Success\""; then + _err "Record cannot be added." + return 1 + fi + _info "Added." + else + _info "Updating the TXT record for $1" + _dns_cloudns_http_api_call "dns/mod-record.json" "domain-name=$zone&record-id=$record_id&record-type=TXT&host=$host&record=$record&ttl=60" + if ! _contains "$response" "\"status\":\"Success\""; then + _err "The TXT record for $1 cannot be updated." + return 1 + fi + _info "Updated." + fi + + return 0 } #Usage: dns_cloudns_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" dns_cloudns_rm() { - _info "Using cloudns" - - if ! _dns_cloudns_init_check; then - return 1 - fi - - if [ -z "$zone" ]; then - zone="$(_dns_cloudns_get_zone_name "$1")" - if [ -z "$zone" ]; then - _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." - return 1 - fi - fi - - host="$(echo "$1" | sed "s/\.$zone\$//")" - record=$2 - record_id=$(_dns_cloudns_get_record_id "$zone" "$host") - - _debug zone "$zone" - _debug host "$host" - _debug record "$record" - _debug record_id "$record_id" - - if [ ! -z "$record_id" ]; then - _info "Deleting the TXT record for $1" - _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=$record_id" - if ! _contains "$response" "\"status\":\"Success\""; then - _err "The TXT record for $1 cannot be deleted." - return 1 - fi - _info "Deleted." - fi - return 0 + _info "Using cloudns" + + if ! _dns_cloudns_init_check; then + return 1 + fi + + if [ -z "$zone" ]; then + zone="$(_dns_cloudns_get_zone_name "$1")" + if [ -z "$zone" ]; then + _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." + return 1 + fi + fi + + host="$(echo "$1" | sed "s/\.$zone\$//")" + record=$2 + record_id=$(_dns_cloudns_get_record_id "$zone" "$host") + + _debug zone "$zone" + _debug host "$host" + _debug record "$record" + _debug record_id "$record_id" + + if [ ! -z "$record_id" ]; then + _info "Deleting the TXT record for $1" + _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=$record_id" + if ! _contains "$response" "\"status\":\"Success\""; then + _err "The TXT record for $1 cannot be deleted." + return 1 + fi + _info "Deleted." + fi + return 0 } #################### Private functions below ################################## _dns_cloudns_init_check() { - if [ ! -z "$CLOUDNS_INIT_CHECK_COMPLETED" ]; then - return 0 - fi - - if [ -z "$CLOUDNS_AUTH_ID" ]; then - _err "CLOUDNS_AUTH_ID is not configured" - return 1 - fi - - if [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then - _err "CLOUDNS_AUTH_PASSWORD is not configured" - return 1 - fi - - _dns_cloudns_http_api_call "dns/login.json" "" - - if ! _contains "$response" "\"status\":\"Success\""; then - _err "Invalid CLOUDNS_AUTH_ID or CLOUDNS_AUTH_PASSWORD. Please check your login credentials." - return 1 - fi - - CLOUDNS_INIT_CHECK_COMPLETED=1 - - return 0 + if [ ! -z "$CLOUDNS_INIT_CHECK_COMPLETED" ]; then + return 0 + fi + + CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}" + CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}" + if [ -z "$CLOUDNS_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then + CLOUDNS_AUTH_ID="" + CLOUDNS_AUTH_PASSWORD="" + _err "You don't specify cloudns api id and password yet." + _err "Please create you id and password and try again." + return 1 + fi + + if [ -z "$CLOUDNS_AUTH_ID" ]; then + _err "CLOUDNS_AUTH_ID is not configured" + return 1 + fi + + if [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then + _err "CLOUDNS_AUTH_PASSWORD is not configured" + return 1 + fi + + _dns_cloudns_http_api_call "dns/login.json" "" + + if ! _contains "$response" "\"status\":\"Success\""; then + _err "Invalid CLOUDNS_AUTH_ID or CLOUDNS_AUTH_PASSWORD. Please check your login credentials." + return 1 + fi + + #save the api id and password to the account conf file. + _saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" + _saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" + + CLOUDNS_INIT_CHECK_COMPLETED=1 + + return 0 } _dns_cloudns_get_zone_name() { - i=2 - while true; do - zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) + i=2 + while true; do + zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) - if [ -z "$zoneForCheck" ]; then - return 1 - fi + if [ -z "$zoneForCheck" ]; then + return 1 + fi - _debug zoneForCheck "$zoneForCheck" + _debug zoneForCheck "$zoneForCheck" - _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" + _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" - if ! _contains "$response" "\"status\":\"Failed\""; then - echo "$zoneForCheck" - return 0 - fi + if ! _contains "$response" "\"status\":\"Failed\""; then + echo "$zoneForCheck" + return 0 + fi - i=$(_math "$i" + 1) - done - return 1 + i=$(_math "$i" + 1) + done + return 1 } _dns_cloudns_get_record_id() { - _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" - if _contains "$response" "\"id\":"; then - echo "$response" | cut -d '"' -f 2 - return 0 - fi - return 1 + _dns_cloudns_http_api_call "dns/records.json" "domain-name=$1&host=$2&type=TXT" + if _contains "$response" "\"id\":"; then + echo "$response" | cut -d '"' -f 2 + return 0 + fi + return 1 } _dns_cloudns_http_api_call() { - method=$1 + method=$1 - _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" - _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" + _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" + _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" - if [ -z "$2" ]; then - data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD" - else - data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" - fi + if [ -z "$2" ]; then + data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD" + else + data="auth-id=$CLOUDNS_AUTH_ID&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" + fi - response="$(_get "$CLOUDNS_API/$method?$data")" + response="$(_get "$CLOUDNS_API/$method?$data")" - _debug2 response "$response" + _debug2 response "$response" - return 0 + return 0 } From 641a2895a6282472fe3c8d52e5289165bf8a3d7d Mon Sep 17 00:00:00 2001 From: hiska Date: Mon, 2 Oct 2017 08:32:36 +0900 Subject: [PATCH 574/620] Create strongswan.sh --- deploy/strongswan.sh | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 deploy/strongswan.sh diff --git a/deploy/strongswan.sh b/deploy/strongswan.sh new file mode 100644 index 00000000..73232785 --- /dev/null +++ b/deploy/strongswan.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env sh + +#Here is a sample custom api script. +#This file name is "myapi.sh" +#So, here must be a method myapi_deploy() +#Which will be called by acme.sh to deploy the cert +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +strongswan_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + cat "$_ckey" >"/etc/ipsec.d/private/$(basename "$_ckey")" + cat "$_ccert" >"/etc/ipsec.d/certs/$(basename "$_ccert")" + cat "$_cca" >"/etc/ipsec.d/cacerts/$(basename "$_cca")" + cat "$_cfullchain" >"/etc/ipsec.d/cacerts/$(basename "$_cfullchain")" + + ipsec reload + + return 0 + +} From afe3283c53930c66017aadbb8e35d5f01b3c714e Mon Sep 17 00:00:00 2001 From: hiska Date: Mon, 2 Oct 2017 08:34:32 +0900 Subject: [PATCH 575/620] Update README.md --- deploy/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/deploy/README.md b/deploy/README.md index c80a567e..31053579 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -97,6 +97,10 @@ acme.sh --deploy -d example.com --deploy-hook cpanel_uapi Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue a separete certificate for each domain. +## 8. Deploy the cert to strongswan +```sh +acme.sh --deploy -d ftp.example.com --deploy-hook strongswan +``` From 372f691fd69a191cb2d718ace2d6f6a16568514e Mon Sep 17 00:00:00 2001 From: hebbet Date: Mon, 2 Oct 2017 15:04:02 +0200 Subject: [PATCH 576/620] unify headlines unify headlines in deploy readme --- deploy/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index af6fc5f3..4e4a7261 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -4,7 +4,7 @@ Before you can deploy your cert, you must [issue the cert first](https://github. Here are the scripts to deploy the certs/key to the server/services. -## 1. Deploy the certs to your cpanel host. +## 1. Deploy the certs to your cpanel host If you want to deploy using cpanel UAPI see 7. @@ -20,7 +20,7 @@ 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. +## 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. @@ -29,11 +29,11 @@ Currently supports Kong-v0.10.x. acme.sh --deploy -d ftp.example.com --deploy-hook kong ``` -## 3. Deploy the cert to remote server through SSH access. +## 3. Deploy the cert to remote server through SSH access (TODO) -## 4. Deploy the cert to local vsftpd server. +## 4. Deploy the cert to local vsftpd server ```sh acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd @@ -55,7 +55,7 @@ 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. +## 5. Deploy the cert to local exim4 server ```sh acme.sh --deploy -d ftp.example.com --deploy-hook exim4 From c924e7c537249a33713e8dc6691ae3311e0b7a23 Mon Sep 17 00:00:00 2001 From: hiska Date: Wed, 4 Oct 2017 06:44:02 +0900 Subject: [PATCH 577/620] remove "return 0" --- deploy/strongswan.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/deploy/strongswan.sh b/deploy/strongswan.sh index 73232785..2de18f88 100644 --- a/deploy/strongswan.sh +++ b/deploy/strongswan.sh @@ -29,6 +29,4 @@ strongswan_deploy() { ipsec reload - return 0 - } From ee56b9cd4e50da0ff36af392676074d3914f12d7 Mon Sep 17 00:00:00 2001 From: sahsanu Date: Sat, 7 Oct 2017 21:31:24 +0200 Subject: [PATCH 578/620] Update ClouDNS.net API doc Update ClouDNS.net API doc to show that CLOUDNS_AUTH_ID and CLOUDNS_AUTH_PASSWORD will be saved in ~/.acme.sh/account.conf --- dnsapi/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index 34b38678..ce8bbfb9 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -420,6 +420,7 @@ 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 From 5f6e3da766ef6ffcefca8d5ced3df4b2fcdd7a62 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 8 Oct 2017 19:45:50 +0800 Subject: [PATCH 579/620] fix https://github.com/Neilpang/acme.sh/issues/1062 change back to use openssl for tls mode. --- acme.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 3e63282d..9b917f7b 100755 --- a/acme.sh +++ b/acme.sh @@ -2054,7 +2054,12 @@ _starttlsserver() { return 1 fi - __S_OPENSSL="socat" + __S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -www -cert $TLS_CERT -key $TLS_KEY " + if [ "$opaddr" ]; then + __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" + else + __S_OPENSSL="$__S_OPENSSL -accept $port" + fi _debug Le_Listen_V4 "$Le_Listen_V4" _debug Le_Listen_V6 "$Le_Listen_V6" @@ -2065,9 +2070,12 @@ _starttlsserver() { fi _debug "$__S_OPENSSL" + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + $__S_OPENSSL -tlsextdebug & + else + $__S_OPENSSL >/dev/null 2>&1 & + fi - #todo listen address - $__S_OPENSSL openssl-listen:$port,cert=$TLS_CERT,key=$TLS_KEY,verify=0,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK'; echo ; echo $content; echo;" & serverproc="$!" sleep 1 _debug serverproc "$serverproc" From 872bfe4757a9593e1a3a6f8e9969ad465ef66beb Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 11 Oct 2017 20:34:56 +0800 Subject: [PATCH 580/620] fix for PR https://github.com/Neilpang/acme.sh/pull/1069 --- dnsapi/dns_aws.sh | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh index 40782573..5a716514 100755 --- a/dnsapi/dns_aws.sh +++ b/dnsapi/dns_aws.sh @@ -87,6 +87,7 @@ _get_root() { _debug "response" "$response" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug2 "Checking domain: $h" if [ -z "$h" ]; then if _contains "$response" "true" && _contains "$response" ""; then _debug "IsTruncated" @@ -102,23 +103,23 @@ _get_root() { fi fi #not valid + _err "Invalid domain" return 1 fi if _contains "$response" "$h."; then hostedzone="$(echo "$response" | sed 's//#&/g' | tr '#' '\n' | _egrep_o "[^<]*<.Id>$h.<.Name>.*false<.PrivateZone>.*<.HostedZone>")" _debug hostedzone "$hostedzone" - if [ -z "$hostedzone" ]; then - _err "Error, can not get hostedzone." + if [ "$hostedzone" ]; then + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>") + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + _err "Can not find domain id: $h" return 1 fi - _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*<.Id>" | head -n 1 | _egrep_o ">.*<" | 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) From 352dd907ac0d90ed5cecf4a9553a59d25ca4ac3d Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 18 Oct 2017 20:27:09 +0800 Subject: [PATCH 581/620] fix https://github.com/Neilpang/acme.sh/issues/1074 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 9b917f7b..d988eb06 100755 --- a/acme.sh +++ b/acme.sh @@ -3135,7 +3135,7 @@ _regAccount() { fi if [ "$code" = '202' ]; then _info "Update account tos info success." - + echo "$response" >"$ACCOUNT_JSON_PATH" CA_KEY_HASH="$(__calcAccountKeyHash)" _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" _savecaconf CA_KEY_HASH "$CA_KEY_HASH" From 7902d10a3aaeff25bd2225e5c2ffd1af1f8e834b Mon Sep 17 00:00:00 2001 From: max2711 <32955673+max2711@users.noreply.github.com> Date: Fri, 20 Oct 2017 14:22:20 +0200 Subject: [PATCH 582/620] remove unused crontab jobs --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e85098e0..97626ba0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ ADD ./ /install_acme.sh/ RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/ -RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | sed 's#> /dev/null##' | crontab - +RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab - RUN for verb in help \ version \ From 4c99c0127b849a8db29151a10b78acb66f78ebdd Mon Sep 17 00:00:00 2001 From: neilpang Date: Wed, 1 Nov 2017 10:14:44 +0800 Subject: [PATCH 583/620] add dev guide --- dnsapi/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dnsapi/README.md b/dnsapi/README.md index ce8bbfb9..cff59c79 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -618,6 +618,7 @@ 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 From 6e93ff8bcac9744ff451181b6feeb7269d2ce1a8 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 10 Nov 2017 23:01:29 +0800 Subject: [PATCH 584/620] fix https://github.com/Neilpang/acme.sh/issues/1106 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index d988eb06..9c8d6d4e 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.4 +VER=2.7.5 PROJECT_NAME="acme.sh" @@ -3474,7 +3474,7 @@ issue() { token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" _debug token "$token" - uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" + uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)" _debug uri "$uri" keyauthorization="$token.$thumbprint" From f62457a24e2f286f309c245b09bd52631f8e00f9 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 13 Nov 2017 20:54:29 +0800 Subject: [PATCH 585/620] fix --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b45cc464..dda8eb10 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ install: openssl version 2>&1 || true; $ACME_OPENSSL_BIN version 2>&1 || true; export PATH="$_old_path"; - else sudo apt-get install socat; + else sudo apt-get -y update && sudo apt-get install -y socat; fi script: From ceafe389afb406b92f77392fd7fe2005cb6b750f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 26 Nov 2017 20:57:02 +0800 Subject: [PATCH 586/620] fix https://github.com/Neilpang/acme.sh/issues/1109 --- dnsapi/dns_freedns.sh | 77 ++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 45 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index 53da4118..ae77d061 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -53,6 +53,8 @@ dns_freedns_add() { 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 @@ -61,7 +63,6 @@ dns_freedns_add() { 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 @@ -70,19 +71,11 @@ dns_freedns_add() { fi return 1 fi + _debug2 htmlpage "$htmlpage" + + subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '
' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep $top_domain)" + _debug2 subdomain_csv "$subdomain_csv" - # Now convert the tables in the HTML to CSV. This litte gem from - # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv - subdomain_csv="$(echo "$htmlpage" \ - | grep -i -e ']*>/\n/Ig' \ - | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ - | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ - | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ - | grep 'edit.php?' \ - | grep "$top_domain")" # 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 @@ -90,30 +83,32 @@ dns_freedns_add() { # Now we have to read through this table and extract the data we need lines="$(echo "$subdomain_csv" | wc -l)" - nl=' -' i=0 found=0 while [ "$i" -lt "$lines" ]; do i="$(_math "$i" + 1)" - line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")" - tmp="$(echo "$line" | cut -d ',' -f 1)" - if [ $found = 0 ] && _startswith "$tmp" "$top_domain"; then + 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" | cut -d ',' -f 2 | sed 's/^.*domain_id=//;s/>.*//')" + DNSdomainid="$(echo "$line" | _egrep_o "edit_domain_id *= *.*>" | cut -d = -f 2 | cut -d '>' -f 1)" + _debug2 DNSdomainid "$DNSdomainid" found=1 else # lines contain DNS records for all subdomains - DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')" - DNStype="$(echo "$line" | cut -d ',' -f 3)" + DNSname="$(echo "$line" | _egrep_o 'edit.php.*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _debug2 DNSname "$DNSname" + DNStype="$(echo "$line" | sed 's/' -f 2 | cut -d '<' -f 1)" + _debug2 DNStype "$DNStype" if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then - DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')" + DNSdataid="$(echo "$line" | _egrep_o 'data_id=.*' | cut -d = -f 2 | cut -d '>' -f 1)" # Now get current value for the TXT record. This method may # not produce accurate results as the value field is truncated # on this webpage. To get full value we would need to load # another page. However we don't really need this so long as # there is only one TXT record for the acme challenge subdomain. - DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')" + DNSvalue="$(echo "$line" | sed 's/' -f 2 | cut -d '<' -f 1)" + _debug2 DNSvalue "$DNSvalue" if [ $found != 0 ]; then break # we are breaking out of the loop at the first match of DNS name @@ -169,8 +164,7 @@ dns_freedns_add() { return 0 else # Delete the old TXT record (with the wrong value) - _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid" - if [ "$?" = "0" ]; then + if _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid"; then # And add in new TXT record with the value provided _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" fi @@ -210,18 +204,9 @@ dns_freedns_rm() { return 1 fi - # Now convert the tables in the HTML to CSV. This litte gem from - # http://stackoverflow.com/questions/1403087/how-can-i-convert-an-html-table-to-csv - subdomain_csv="$(echo "$htmlpage" \ - | grep -i -e ']*>/\n/Ig' \ - | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ - | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ - | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ - | grep 'edit.php?' \ - | grep "$fulldomain")" + subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep $fulldomain)" + _debug2 subdomain_csv "$subdomain_csv" + # The above beauty ends with striping out rows that do not have an # href to edit.php and do not have the domain name we are looking for. # So all we should be left with is CSV of table of subdomains we are @@ -229,19 +214,21 @@ dns_freedns_rm() { # Now we have to read through this table and extract the data we need lines="$(echo "$subdomain_csv" | wc -l)" - nl=' -' i=0 found=0 while [ "$i" -lt "$lines" ]; do i="$(_math "$i" + 1)" - line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")" - DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')" - DNStype="$(echo "$line" | cut -d ',' -f 3)" + line="$(echo "$subdomain_csv" | sed -n ${i}p)" + _debug2 line "$line" + DNSname="$(echo "$line" | _egrep_o 'edit.php.*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _debug2 DNSname "$DNSname" + DNStype="$(echo "$line" | sed 's/' -f 2 | cut -d '<' -f 1)" + _debug2 DNStype "$DNStype" if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then - DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')" - DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')" - _debug "DNSvalue: $DNSvalue" + 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)" + _debug2 DNSvalue "$DNSvalue" # if [ "$DNSvalue" = "$txtvalue" ]; then # Testing value match fails. Website is truncating the value # field. So for now we will assume that there is only one TXT From b615cce92d69c0de937a15538ef764a21fda33b5 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 2 Dec 2017 19:54:33 +0800 Subject: [PATCH 587/620] fix https://github.com/Neilpang/acme.sh/issues/1127 --- Dockerfile | 2 +- acme.sh | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 97626ba0..b2866739 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine +FROM alpine:3.6 RUN apk update -f \ && apk --no-cache add -f \ diff --git a/acme.sh b/acme.sh index 9c8d6d4e..98f4067a 100755 --- a/acme.sh +++ b/acme.sh @@ -463,8 +463,7 @@ if _exists xargs && [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then fi _h2b() { - if _exists xxd; then - xxd -r -p + if _exists xxd && xxd -r -p 2>/dev/null; then return fi From 529cbc037900506969e996e98903d7e60b211751 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 3 Dec 2017 12:51:51 +0800 Subject: [PATCH 588/620] run ci in docker --- .travis.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dda8eb10..ab5632dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,14 @@ language: shell sudo: required +dist: trusty os: - linux - osx +services: + - docker + env: global: - SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64 @@ -30,7 +34,6 @@ install: openssl version 2>&1 || true; $ACME_OPENSSL_BIN version 2>&1 || true; export PATH="$_old_path"; - else sudo apt-get -y update && sudo apt-get install -y socat; fi script: @@ -44,7 +47,7 @@ script: - 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 - - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./rundocker.sh testplat ubuntu:latest ; fi - if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi From dcf8457f4d4b6d80236557fbc77ecd7060f56ec0 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 3 Dec 2017 13:16:37 +0800 Subject: [PATCH 589/620] fix format --- dnsapi/dns_freedns.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_freedns.sh b/dnsapi/dns_freedns.sh index ae77d061..afd8b796 100755 --- a/dnsapi/dns_freedns.sh +++ b/dnsapi/dns_freedns.sh @@ -73,7 +73,7 @@ dns_freedns_add() { fi _debug2 htmlpage "$htmlpage" - subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep $top_domain)" + subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep "$top_domain")" _debug2 subdomain_csv "$subdomain_csv" # The above beauty ends with striping out rows that do not have an @@ -87,7 +87,7 @@ dns_freedns_add() { found=0 while [ "$i" -lt "$lines" ]; do i="$(_math "$i" + 1)" - line="$(echo "$subdomain_csv" | sed -n ${i}p)" + 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 @@ -204,7 +204,7 @@ dns_freedns_rm() { return 1 fi - subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep $fulldomain)" + subdomain_csv="$(echo "$htmlpage" | tr -d "\n\r" | _egrep_o '' | sed 's//@/g' | tr '@' '\n' | grep edit.php | grep "$fulldomain")" _debug2 subdomain_csv "$subdomain_csv" # The above beauty ends with striping out rows that do not have an @@ -218,7 +218,7 @@ dns_freedns_rm() { found=0 while [ "$i" -lt "$lines" ]; do i="$(_math "$i" + 1)" - line="$(echo "$subdomain_csv" | sed -n ${i}p)" + line="$(echo "$subdomain_csv" | sed -n "${i}p")" _debug2 line "$line" DNSname="$(echo "$line" | _egrep_o 'edit.php.*' | cut -d '>' -f 2 | cut -d '<' -f 1)" _debug2 DNSname "$DNSname" From 9eeebb147f9747a68e567ac40e202c51dc7aa4a3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sun, 3 Dec 2017 20:57:25 +0800 Subject: [PATCH 590/620] fix osx build --- .travis.yml | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index ab5632dd..b6b57423 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,20 +22,10 @@ addons: install: - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then - brew update && brew install openssl socat; - brew info openssl; - ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; - ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/; - ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl; - _old_path="$PATH"; - echo "PATH=$PATH"; - export PATH=""; - export ACME_OPENSSL_BIN="/usr/local/openssl"; - openssl version 2>&1 || true; - $ACME_OPENSSL_BIN version 2>&1 || true; - export PATH="$_old_path"; + brew update && brew install socat; + export PATH="/usr/local/opt/openssl@1.1/bin:$PATH" ; fi - + script: - echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)" - command -V openssl && openssl version From 0ca3141088ead8a638c5067519e6c97216f699cf Mon Sep 17 00:00:00 2001 From: Aarup Date: Wed, 6 Dec 2017 11:50:54 +0100 Subject: [PATCH 591/620] Added support for UnoEuro api --- dnsapi/dns_unoeuro.sh | 194 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 dnsapi/dns_unoeuro.sh diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh new file mode 100644 index 00000000..985b441d --- /dev/null +++ b/dnsapi/dns_unoeuro.sh @@ -0,0 +1,194 @@ +#!/usr/bin/env sh + +# +#Uno_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#Uno_User="UExxxxxx" + +Uno_Api="https://api.unoeuro.com/1/$Uno_User/$Uno_Key" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_unoeuro_add() { + fulldomain=$1 + txtvalue=$2 + + Uno_Key="${Uno_Key:-$(_readaccountconf_mutable Uno_Key)}" + Uno_User="${Uno_User:-$(_readaccountconf_mutable Uno_User)}" + if [ -z "$Uno_Key" ] || [ -z "$Uno_User" ]; then + Uno_Key="" + Uno_User="" + _err "You haven't specified a UnoEuro api key and account yet." + _err "Please create your key and try again." + return 1 + fi + + if ! _contains "$Uno_User" "UE"; then + _err "It seems that the Uno_User=$Uno_User is not a valid email address." + _err "Please check and retry." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable Uno_Key "$Uno_Key" + _saveaccountconf_mutable Uno_User "$Uno_User" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _uno_rest GET "my/products/$h/dns/records" + + if ! _contains "$response" "\"status\": 200" >/dev/null; then + _err "Error" + return 1 + fi + + if ! _contains "$response" "$_sub_domain" >/dev/null; then + _info "Adding record" + if _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}"; then + if _contains "$response" "\"status\": 200" >/dev/null; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | head -1 | _egrep_o "[0-9]{1,}") + _debug "record_id" "$record_id" + + _uno_rest PUT "my/products/$h/dns/records/$record_id" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120}" + if _contains "$response" "\"status\": 200" >/dev/null; then + _info "Updated, OK" + return 0 + fi + _err "Update error" + return 1 + fi + +} + +#fulldomain txtvalue +dns_unoeuro_rm() { + fulldomain=$1 + txtvalue=$2 + + Uno_Key="${Uno_Key:-$(_readaccountconf_mutable Uno_Key)}" + Uno_User="${Uno_User:-$(_readaccountconf_mutable Uno_User)}" + if [ -z "$Uno_Key" ] || [ -z "$Uno_User" ]; then + Uno_Key="" + Uno_User="" + _err "You haven't specified a UnoEuro api key and account yet." + _err "Please create your key and try again." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _uno_rest GET "my/products/$h/dns/records" + + if ! _contains "$response" "\"status\": 200" >/dev/null; then + _err "Error" + return 1 + fi + + if ! _contains "$response" "$_sub_domain" >/dev/null; then + _info "Don't need to remove." + else + record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | head -1 | _egrep_o "[0-9]{1,}") + _debug "record_id" "$record_id" + + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + + if ! _uno_rest DELETE "my/products/$h/dns/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" "\"status\": 200" + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _uno_rest GET "my/products/$h/dns/records"; then + return 1 + fi + + if _contains "$response" "\"status\": 200" >/dev/null; then + _domain_id=$h + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_uno_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + #export _H1="X-Auth-Email: $Uno_User" + #export _H2="X-Auth-Key: $Uno_Key" + export _H1="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$Uno_Api/$ep" "" "$m")" + else + response="$(_get "$Uno_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} From 70702e41e994ce98dac23b06bf59e2bbcdf4f560 Mon Sep 17 00:00:00 2001 From: Aarup Date: Wed, 6 Dec 2017 11:55:29 +0100 Subject: [PATCH 592/620] Use _head_n --- dnsapi/dns_unoeuro.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index 985b441d..4774187d 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -65,7 +65,7 @@ dns_unoeuro_add() { _err "Add txt record error." else _info "Updating record" - record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | head -1 | _egrep_o "[0-9]{1,}") + record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | _head_n -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}" @@ -114,7 +114,7 @@ dns_unoeuro_rm() { if ! _contains "$response" "$_sub_domain" >/dev/null; then _info "Don't need to remove." else - record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | head -1 | _egrep_o "[0-9]{1,}") + record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | _head_n -1 | _egrep_o "[0-9]{1,}") _debug "record_id" "$record_id" if [ -z "$record_id" ]; then From 78712245f70800f4bd4875732271b9e96af1c4f9 Mon Sep 17 00:00:00 2001 From: Aarup Date: Wed, 6 Dec 2017 12:13:40 +0100 Subject: [PATCH 593/620] Add UnoEuro to README --- README.md | 1 + dnsapi/README.md | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/README.md b/README.md index 7d4353c6..9e64e613 100644 --- a/README.md +++ b/README.md @@ -339,6 +339,7 @@ You don't have to do anything manually! 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/) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index cff59c79..5fdcd849 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -602,6 +602,22 @@ The `HE_Username` and `HE_Password` settings will be saved in `~/.acme.sh/accoun 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. + # Use custom API If your API is not supported yet, you can write your own DNS API. From 657334fb67e25b5503d02fc9abba2f5a2dbca410 Mon Sep 17 00:00:00 2001 From: speedmann Date: Thu, 7 Dec 2017 11:47:01 +0100 Subject: [PATCH 594/620] Add support for inwx.de API --- README.md | 1 + dnsapi/README.md | 17 +++ dnsapi/dns_inwx.sh | 365 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 383 insertions(+) create mode 100755 dnsapi/dns_inwx.sh diff --git a/README.md b/README.md index 7d4353c6..e8f94644 100644 --- a/README.md +++ b/README.md @@ -339,6 +339,7 @@ You don't have to do anything manually! 1. Dyn Managed DNS API 1. Yandex PDD API (https://pdd.yandex.ru) 1. Hurricane Electric DNS service (https://dns.he.net) +1. INWX (https://www.inwx.de/) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index cff59c79..768f69a3 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -602,6 +602,23 @@ The `HE_Username` and `HE_Password` settings will be saved in `~/.acme.sh/accoun Please report any issues to https://github.com/angel333/acme.sh or to . +## 31. Use INWX + +INWX offers an xmlrpc api 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. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh new file mode 100755 index 00000000..db5b18c8 --- /dev/null +++ b/dnsapi/dns_inwx.sh @@ -0,0 +1,365 @@ +#!/usr/local/bin/bash + +# +#INWX_User="username" +# +#INWX_Password="password" + +INWX_Api="https://api.domrobot.com/xmlrpc/" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_inwx_add() { + fulldomain=$1 + txtvalue=$2 + + INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}" + INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}" + if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then + INWX_User="" + INWX_Password="" + _err "You don't specify inwx user and password yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable INWX_User "$INWX_User" + _saveaccountconf_mutable INWX_Password "$INWX_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + + + printf -v xml_content ' + + nameserver.info + + + + + + domain + + %s + + + + type + + TXT + + + + name + + %s + + + + + + + ' $_domain $_sub_domain + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "Command completed successfully" > /dev/null; then + _err "Error could net get txt records" + return 1 + fi + + if ! printf "%s" "$response" | grep "count" -q; then + _info "Adding record" + _inwx_add_record $_domain $_sub_domain $txtvalue + else + _record_id=$(printf '%s' $response | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') + _info "Updating record" + _inwx_update_record $_record_id $txtvalue + fi + +} + +#fulldomain txtvalue +dns_inwx_rm() { + + fulldomain=$1 + txtvalue=$2 + + INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}" + INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}" + if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then + INWX_User="" + INWX_Password="" + _err "You don't specify inwx user and password yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable INWX_User "$INWX_User" + _saveaccountconf_mutable INWX_Password "$INWX_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + + + printf -v xml_content ' + + nameserver.info + + + + + + domain + + %s + + + + type + + TXT + + + + name + + %s + + + + + + + ' $_domain $_sub_domain + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "Command completed successfully" > /dev/null; then + _err "Error could not get txt records" + return 1 + fi + + if ! printf "%s" "$response" | grep "count" -q; then + _info "Do not need to delete record" + else + _record_id=$(printf '%s' $response | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') + _info "Deleting record" + _inwx_delete_record $_record_id + fi + + +} + +#################### Private functions below ################################## + +_inwx_login() { + + printf -v xml_content ' + + account.login + + + + + + user + + %s + + + + pass + + %s + + + + + + + ' $INWX_User $INWX_Password + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')" + +} + +_get_root() { + domain=$1 + _debug "get root" + + domain=$1 + i=2 + p=1 + + + export _H1=$(_inwx_login) + printf -v xml_content ' + + nameserver.list + ' + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "$h"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 + +} + +_inwx_delete_record() { + record_id=$1 + printf -v xml_content ' + + nameserver.deleteRecord + + + + + + id + + %s + + + + + + + ' $record_id + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then + _err "Error" + return 1 + fi + return 0 + + +} + +_inwx_update_record() { + record_id=$1 + txtval=$2 + printf -v xml_content ' + + nameserver.updateRecord + + + + + + content + + %s + + + + id + + %s + + + + + + + ' $txtval $record_id + + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then + _err "Error" + return 1 + fi + return 0 + +} + +_inwx_add_record() { + + domain=$1 + sub_domain=$2 + txtval=$3 + + _debug domain: $domain + _debug value: $txtval + _debug subd: $sub_domain + + printf -v xml_content ' + + nameserver.createRecord + + + + + + domain + + %s + + + + type + + TXT + + + + content + + %s + + + + name + + %s + + + + + + + ' $domain $txtval $sub_domain + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then + _err "Error" + return 1 + fi + return 0 +} From a8202d4b3780e04b3b68cc7196ee47871e63ee3d Mon Sep 17 00:00:00 2001 From: speedmann Date: Thu, 7 Dec 2017 12:05:03 +0100 Subject: [PATCH 595/620] Fix CI issues --- dnsapi/dns_inwx.sh | 64 +++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index db5b18c8..9e2302b7 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -35,11 +35,9 @@ dns_inwx_add() { fi _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - _debug "Getting txt records" - - printf -v xml_content ' + printf -v xml_content ' nameserver.info @@ -68,21 +66,21 @@ dns_inwx_add() { - ' $_domain $_sub_domain + ' "$_domain" "$_sub_domain" response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - if ! printf "%s" "$response" | grep "Command completed successfully" > /dev/null; then + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then _err "Error could net get txt records" return 1 fi if ! printf "%s" "$response" | grep "count" -q; then _info "Adding record" - _inwx_add_record $_domain $_sub_domain $txtvalue + _inwx_add_record "$_domain" "$_sub_domain" "$txtvalue" else - _record_id=$(printf '%s' $response | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') + _record_id=$(printf '%s' "$response" | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') _info "Updating record" - _inwx_update_record $_record_id $txtvalue + _inwx_update_record "$_record_id" "$txtvalue" fi } @@ -117,8 +115,7 @@ dns_inwx_rm() { _debug "Getting txt records" - - printf -v xml_content ' + printf -v xml_content ' nameserver.info @@ -147,10 +144,10 @@ dns_inwx_rm() { - ' $_domain $_sub_domain + ' "$_domain" "$_sub_domain" response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - if ! printf "%s" "$response" | grep "Command completed successfully" > /dev/null; then + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then _err "Error could not get txt records" return 1 fi @@ -158,12 +155,11 @@ dns_inwx_rm() { if ! printf "%s" "$response" | grep "count" -q; then _info "Do not need to delete record" else - _record_id=$(printf '%s' $response | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') + _record_id=$(printf '%s' "$response" | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') _info "Deleting record" - _inwx_delete_record $_record_id + _inwx_delete_record "$_record_id" fi - } #################### Private functions below ################################## @@ -196,26 +192,26 @@ _inwx_login() { ' $INWX_User $INWX_Password response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - + printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')" } _get_root() { - domain=$1 + domain=$1 _debug "get root" domain=$1 i=2 p=1 - - export _H1=$(_inwx_login) + _H1=$(_inwx_login) + export _H1 printf -v xml_content ' nameserver.list ' - + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" while true; do h=$(printf "%s" "$domain" | cut -d . -f $i-100) @@ -256,17 +252,16 @@ _inwx_delete_record() { - ' $record_id - + ' "$record_id" + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then _err "Error" return 1 fi return 0 - - + } _inwx_update_record() { @@ -295,17 +290,16 @@ _inwx_update_record() { - ' $txtval $record_id - - + ' "$txtval" "$record_id" + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then _err "Error" return 1 fi return 0 - + } _inwx_add_record() { @@ -314,10 +308,6 @@ _inwx_add_record() { sub_domain=$2 txtval=$3 - _debug domain: $domain - _debug value: $txtval - _debug subd: $sub_domain - printf -v xml_content ' nameserver.createRecord @@ -353,10 +343,10 @@ _inwx_add_record() { - ' $domain $txtval $sub_domain - + ' "$domain" "$txtval" "$sub_domain" + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then _err "Error" return 1 From ecba959dd99cda64d72c88c1d9c7d77894f72f80 Mon Sep 17 00:00:00 2001 From: speedmann Date: Thu, 7 Dec 2017 13:07:05 +0100 Subject: [PATCH 596/620] Fix missed whitespaces --- dnsapi/dns_inwx.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index 9e2302b7..b02d1fb1 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -155,7 +155,7 @@ dns_inwx_rm() { if ! printf "%s" "$response" | grep "count" -q; then _info "Do not need to delete record" else - _record_id=$(printf '%s' "$response" | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') + _record_id=$(printf '%s' "$response" | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') _info "Deleting record" _inwx_delete_record "$_record_id" fi @@ -253,7 +253,7 @@ _inwx_delete_record() { ' "$record_id" - + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then @@ -261,7 +261,7 @@ _inwx_delete_record() { return 1 fi return 0 - + } _inwx_update_record() { @@ -293,13 +293,13 @@ _inwx_update_record() { ' "$txtval" "$record_id" response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then _err "Error" return 1 fi return 0 - + } _inwx_add_record() { From a00169451fc21653763efefd0dc7938362a0e5fa Mon Sep 17 00:00:00 2001 From: speedmann Date: Thu, 7 Dec 2017 13:10:59 +0100 Subject: [PATCH 597/620] Change bash to sh to fit project requirements --- dnsapi/dns_inwx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index b02d1fb1..78e101e9 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -1,4 +1,4 @@ -#!/usr/local/bin/bash +#!/usr/local/bin/sh # #INWX_User="username" From 4a9f607d318a6a5e451f6962e44697c857580eea Mon Sep 17 00:00:00 2001 From: JAA Date: Thu, 7 Dec 2017 13:53:27 +0100 Subject: [PATCH 598/620] Cleanup --- dnsapi/dns_unoeuro.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index 4774187d..f48b8b9d 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -5,7 +5,7 @@ # #Uno_User="UExxxxxx" -Uno_Api="https://api.unoeuro.com/1/$Uno_User/$Uno_Key" +Uno_Api="https://api.unoeuro.com/1" ######## Public functions ##################### @@ -25,7 +25,7 @@ dns_unoeuro_add() { fi if ! _contains "$Uno_User" "UE"; then - _err "It seems that the Uno_User=$Uno_User is not a valid email address." + _err "It seems that the Uno_User=$Uno_User is not a valid username." _err "Please check and retry." return 1 fi @@ -94,6 +94,12 @@ dns_unoeuro_rm() { return 1 fi + if ! _contains "$Uno_User" "UE"; then + _err "It seems that the Uno_User=$Uno_User is not a valid username." + _err "Please check and retry." + return 1 + fi + _debug "First detect the root zone" if ! _get_root "$fulldomain"; then _err "invalid domain" @@ -174,15 +180,13 @@ _uno_rest() { data="$3" _debug "$ep" - #export _H1="X-Auth-Email: $Uno_User" - #export _H2="X-Auth-Key: $Uno_Key" export _H1="Content-Type: application/json" if [ "$m" != "GET" ]; then _debug data "$data" - response="$(_post "$data" "$Uno_Api/$ep" "" "$m")" + response="$(_post "$data" "$Uno_Api/$Uno_User/$Uno_Key/$ep" "" "$m")" else - response="$(_get "$Uno_Api/$ep")" + response="$(_get "$Uno_Api/$Uno_User/$Uno_Key/$ep")" fi if [ "$?" != "0" ]; then From b91c0a0616f11f3475d21269883cf3107201581f Mon Sep 17 00:00:00 2001 From: JAA Date: Thu, 7 Dec 2017 13:53:40 +0100 Subject: [PATCH 599/620] Don't use grep -B --- dnsapi/dns_unoeuro.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index f48b8b9d..d19e9eb4 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -65,7 +65,7 @@ dns_unoeuro_add() { _err "Add txt record error." else _info "Updating record" - record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | _head_n -1 | _egrep_o "[0-9]{1,}") + record_id=$(echo "$response" | sed -n -e "/$_sub_domain/{x;p;d;}" -e x | _head_n -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}" @@ -120,7 +120,7 @@ dns_unoeuro_rm() { if ! _contains "$response" "$_sub_domain" >/dev/null; then _info "Don't need to remove." else - record_id=$(echo "$response" | grep -B 1 "$_sub_domain" | _head_n -1 | _egrep_o "[0-9]{1,}") + record_id=$(echo "$response" | sed -n -e "/$_sub_domain/{x;p;d;}" -e x | _head_n -1 | _egrep_o "[0-9]{1,}") _debug "record_id" "$record_id" if [ -z "$record_id" ]; then From 9a1f769828c426b26589110b70f324bde4e6c7e2 Mon Sep 17 00:00:00 2001 From: speedmann Date: Thu, 7 Dec 2017 14:18:54 +0100 Subject: [PATCH 600/620] Avoid usage of `sed -E` `grep -q` and `printf -v` --- dnsapi/dns_inwx.sh | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index 78e101e9..2a2895f1 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -37,7 +37,7 @@ dns_inwx_add() { _debug _domain "$_domain" _debug "Getting txt records" - printf -v xml_content ' + xml_content=$(printf ' nameserver.info @@ -66,7 +66,7 @@ dns_inwx_add() { - ' "$_domain" "$_sub_domain" + ' "$_domain" "$_sub_domain") response="$(_post "$xml_content" "$INWX_Api" "" "POST")" if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then @@ -74,11 +74,11 @@ dns_inwx_add() { return 1 fi - if ! printf "%s" "$response" | grep "count" -q; then + if ! printf "%s" "$response" | grep "count" >/dev/null; then _info "Adding record" _inwx_add_record "$_domain" "$_sub_domain" "$txtvalue" else - _record_id=$(printf '%s' "$response" | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') + _record_id=$(printf '%s' "$response" | _egrep_o '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | egrep -o '[0-9]+') _info "Updating record" _inwx_update_record "$_record_id" "$txtvalue" fi @@ -115,7 +115,7 @@ dns_inwx_rm() { _debug "Getting txt records" - printf -v xml_content ' + xml_content=$(printf ' nameserver.info @@ -144,7 +144,7 @@ dns_inwx_rm() { - ' "$_domain" "$_sub_domain" + ' "$_domain" "$_sub_domain") response="$(_post "$xml_content" "$INWX_Api" "" "POST")" if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then @@ -152,10 +152,10 @@ dns_inwx_rm() { return 1 fi - if ! printf "%s" "$response" | grep "count" -q; then + if ! printf "%s" "$response" | grep "count" >/dev/null; then _info "Do not need to delete record" else - _record_id=$(printf '%s' "$response" | sed -nE 's/.*(record){1}(.*)(id<\/name>)([0-9]+){1}.*/\4/p') + _record_id=$(printf '%s' "$response" | _egrep_o '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | egrep -o '[0-9]+') _info "Deleting record" _inwx_delete_record "$_record_id" fi @@ -166,7 +166,7 @@ dns_inwx_rm() { _inwx_login() { - printf -v xml_content ' + xml_content=$(printf ' account.login @@ -189,7 +189,7 @@ _inwx_login() { - ' $INWX_User $INWX_Password + ' $INWX_User $INWX_Password) response="$(_post "$xml_content" "$INWX_Api" "" "POST")" @@ -207,7 +207,7 @@ _get_root() { _H1=$(_inwx_login) export _H1 - printf -v xml_content ' + xml_content=' nameserver.list ' @@ -235,7 +235,7 @@ _get_root() { _inwx_delete_record() { record_id=$1 - printf -v xml_content ' + xml_content=$(printf ' nameserver.deleteRecord @@ -252,7 +252,7 @@ _inwx_delete_record() { - ' "$record_id" + ' "$record_id") response="$(_post "$xml_content" "$INWX_Api" "" "POST")" @@ -267,7 +267,7 @@ _inwx_delete_record() { _inwx_update_record() { record_id=$1 txtval=$2 - printf -v xml_content ' + xml_content=$(printf ' nameserver.updateRecord @@ -290,7 +290,7 @@ _inwx_update_record() { - ' "$txtval" "$record_id" + ' "$txtval" "$record_id") response="$(_post "$xml_content" "$INWX_Api" "" "POST")" @@ -308,7 +308,7 @@ _inwx_add_record() { sub_domain=$2 txtval=$3 - printf -v xml_content ' + xml_content=$(printf ' nameserver.createRecord @@ -343,7 +343,7 @@ _inwx_add_record() { - ' "$domain" "$txtval" "$sub_domain" + ' "$domain" "$txtval" "$sub_domain") response="$(_post "$xml_content" "$INWX_Api" "" "POST")" From 5911594906f07aa2db4b7d3256388e7514f28b92 Mon Sep 17 00:00:00 2001 From: speedmann Date: Thu, 7 Dec 2017 14:21:37 +0100 Subject: [PATCH 601/620] Fix egrep invocation --- dnsapi/dns_inwx.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index 2a2895f1..ae20074b 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -78,7 +78,7 @@ dns_inwx_add() { _info "Adding record" _inwx_add_record "$_domain" "$_sub_domain" "$txtvalue" else - _record_id=$(printf '%s' "$response" | _egrep_o '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | egrep -o '[0-9]+') + _record_id=$(printf '%s' "$response" | _egrep_o '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | _egrep_o '[0-9]+') _info "Updating record" _inwx_update_record "$_record_id" "$txtvalue" fi @@ -155,7 +155,7 @@ dns_inwx_rm() { if ! printf "%s" "$response" | grep "count" >/dev/null; then _info "Do not need to delete record" else - _record_id=$(printf '%s' "$response" | _egrep_o '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | egrep -o '[0-9]+') + _record_id=$(printf '%s' "$response" | _egrep_o '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | _egrep_o '[0-9]+') _info "Deleting record" _inwx_delete_record "$_record_id" fi From f87890cb4b534feecd23dd2e7042e8601f15a3c3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Thu, 7 Dec 2017 21:32:17 +0800 Subject: [PATCH 602/620] v2.7.6 fix ECC 384 signature https://github.com/Neilpang/acme.sh/issues/1130 https://github.com/Neilpang/acme.sh/issues/990 --- acme.sh | 149 ++++++++++++++++++++++---------------------------------- 1 file changed, 57 insertions(+), 92 deletions(-) diff --git a/acme.sh b/acme.sh index 98f4067a..0755f78a 100755 --- a/acme.sh +++ b/acme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VER=2.7.5 +VER=2.7.6 PROJECT_NAME="acme.sh" @@ -15,7 +15,7 @@ _SUB_FOLDERS="dnsapi deploy" _OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory" -DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" + DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" DEFAULT_ACCOUNT_EMAIL="" @@ -900,17 +900,11 @@ _sign() { fi _sign_openssl="${ACME_OPENSSL_BIN:-openssl} dgst -sign $keyfile " - if [ "$alg" = "sha256" ]; then - _sign_openssl="$_sign_openssl -$alg" - else - _err "$alg is not supported yet" - return 1 - fi if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then - $_sign_openssl | _base64 + $_sign_openssl -$alg | _base64 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then - if ! _signedECText="$($_sign_openssl | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then + if ! _signedECText="$($_sign_openssl -sha$__ECC_KEY_LEN | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then _err "Sign failed: $_sign_openssl" _err "Key file: $keyfile" _err "Key content:$(wc -l <"$keyfile") lines" @@ -1433,7 +1427,11 @@ _calcjwk() { _debug "EC key" crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" _debug3 crv "$crv" - + __ECC_KEY_LEN=$(echo "$crv" | cut -d "-" -f 2) + if [ "$__ECC_KEY_LEN" = "521" ]; then + __ECC_KEY_LEN=512 + fi + _debug3 __ECC_KEY_LEN "$__ECC_KEY_LEN" if [ -z "$crv" ]; then _debug "Let's try ASN1 OID" crv_oid="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" @@ -1441,12 +1439,15 @@ _calcjwk() { case "${crv_oid}" in "prime256v1") crv="P-256" + __ECC_KEY_LEN=256 ;; "secp384r1") crv="P-384" + __ECC_KEY_LEN=384 ;; "secp521r1") crv="P-521" + __ECC_KEY_LEN=512 ;; *) _err "ECC oid : $crv_oid" @@ -1488,9 +1489,9 @@ _calcjwk() { jwk='{"crv": "'$crv'", "kty": "EC", "x": "'$x64'", "y": "'$y64'"}' _debug3 jwk "$jwk" - JWK_HEADER='{"alg": "ES256", "jwk": '$jwk'}' + JWK_HEADER='{"alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}' JWK_HEADERPLACE_PART1='{"nonce": "' - JWK_HEADERPLACE_PART2='", "alg": "ES256", "jwk": '$jwk'}' + JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}' else _err "Only RSA or EC key is supported." return 1 @@ -2160,17 +2161,6 @@ _initAPI() { _api_server="${1:-$ACME_DIRECTORY}" _debug "_init api for server: $_api_server" - if [ "$_api_server" = "$DEFAULT_CA" ]; then - #just for performance, hardcode the default entry points - export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" - export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz" - export ACME_NEW_ORDER="https://acme-v01.api.letsencrypt.org/acme/new-cert" - export ACME_NEW_ORDER_RES="new-cert" - export ACME_NEW_ACCOUNT="https://acme-v01.api.letsencrypt.org/acme/new-reg" - export ACME_NEW_ACCOUNT_RES="new-reg" - export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert" - fi - if [ -z "$ACME_NEW_ACCOUNT" ]; then response=$(_get "$_api_server") if [ "$?" != "0" ]; then @@ -2209,14 +2199,18 @@ _initAPI() { ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_NEW_NONCE + + ACME_AGREEMENT=$(echo "$response" | _egrep_o 'terms-of-service" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_AGREEMENT - fi + _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" + _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" + _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" + _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" + _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" + _debug "ACME_AGREEMENT" "$ACME_AGREEMENT" - _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" - _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" - _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" - _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" - _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" + fi } #[domain] [keylength or isEcc flag] @@ -3058,7 +3052,7 @@ __calc_account_thumbprint() { _regAccount() { _initpath _reg_length="$1" - + _debug3 _regAccount "$_regAccount" mkdir -p "$CA_DIR" if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" @@ -3081,75 +3075,46 @@ _regAccount() { return 1 fi _initAPI - _updateTos="" _reg_res="$ACME_NEW_ACCOUNT_RES" - while true; do - _debug AGREEMENT "$AGREEMENT" + regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' + if [ "$ACCOUNT_EMAIL" ]; then + regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' + fi - regjson='{"resource": "'$_reg_res'", "agreement": "'$AGREEMENT'"}' + if [ -z "$_updateTos" ]; then + _info "Registering account" - if [ "$ACCOUNT_EMAIL" ]; then - regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' - fi + if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then + _err "Register account Error: $response" + return 1 + fi - if [ -z "$_updateTos" ]; then - _info "Registering account" + if [ "$code" = "" ] || [ "$code" = '201' ]; then + echo "$response" >"$ACCOUNT_JSON_PATH" + _info "Registered" + elif [ "$code" = '409' ]; then + _info "Already registered" + else + _err "Register account Error: $response" + return 1 + fi - if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then - _err "Register account Error: $response" - return 1 - fi + _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" + _debug "_accUri" "$_accUri" + _savecaconf "ACCOUNT_URL" "$_accUri" - if [ "$code" = "" ] || [ "$code" = '201' ]; then - echo "$response" >"$ACCOUNT_JSON_PATH" - _info "Registered" - elif [ "$code" = '409' ]; then - _info "Already registered" - else - _err "Register account Error: $response" - return 1 - fi + echo "$response" >"$ACCOUNT_JSON_PATH" + CA_KEY_HASH="$(__calcAccountKeyHash)" + _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" + _savecaconf CA_KEY_HASH "$CA_KEY_HASH" - _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" - _debug "_accUri" "$_accUri" - _savecaconf "ACCOUNT_URL" "$_accUri" - _tos="$(echo "$responseHeaders" | grep "^Link:.*rel=\"terms-of-service\"" | _head_n 1 | _egrep_o "<.*>" | tr -d '<>')" - _debug "_tos" "$_tos" - if [ -z "$_tos" ]; then - _debug "Use default tos: $DEFAULT_AGREEMENT" - _tos="$DEFAULT_AGREEMENT" - fi - if [ "$_tos" != "$AGREEMENT" ]; then - _updateTos=1 - AGREEMENT="$_tos" - _reg_res="reg" - continue - fi + if [ "$code" = '403' ]; then + _err "It seems that the account key is already deactivated, please use a new account key." + return 1 + fi - else - _debug "Update tos: $_tos" - if ! _send_signed_request "$_accUri" "$regjson"; then - _err "Update tos error." - return 1 - fi - if [ "$code" = '202' ]; then - _info "Update account tos info success." - echo "$response" >"$ACCOUNT_JSON_PATH" - CA_KEY_HASH="$(__calcAccountKeyHash)" - _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" - _savecaconf CA_KEY_HASH "$CA_KEY_HASH" - elif [ "$code" = '403' ]; then - _err "It seems that the account key is already deactivated, please use a new account key." - return 1 - else - _err "Update account error." - return 1 - fi - fi - ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)" - _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT" - return 0 - done + ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)" + _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT" } From db3043553cbfb9ca05f5a6807590603ee381a80a Mon Sep 17 00:00:00 2001 From: JAA Date: Thu, 7 Dec 2017 14:52:09 +0100 Subject: [PATCH 603/620] Also don't use sed --- dnsapi/dns_unoeuro.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index d19e9eb4..6b582ddd 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -53,6 +53,7 @@ dns_unoeuro_add() { 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" @@ -65,7 +66,9 @@ dns_unoeuro_add() { _err "Add txt record error." else _info "Updating record" - record_id=$(echo "$response" | sed -n -e "/$_sub_domain/{x;p;d;}" -e x | _head_n -1 | _egrep_o "[0-9]{1,}") + record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) + record_line_number=$(($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}" @@ -76,7 +79,6 @@ dns_unoeuro_add() { _err "Update error" return 1 fi - } #fulldomain txtvalue @@ -120,7 +122,9 @@ dns_unoeuro_rm() { if ! _contains "$response" "$_sub_domain" >/dev/null; then _info "Don't need to remove." else - record_id=$(echo "$response" | sed -n -e "/$_sub_domain/{x;p;d;}" -e x | _head_n -1 | _egrep_o "[0-9]{1,}") + record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) + record_line_number=$(($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 From 1f635b90e76a5fb61a92f038a20a78b5381b1ea2 Mon Sep 17 00:00:00 2001 From: Aarup Date: Fri, 8 Dec 2017 08:26:52 +0100 Subject: [PATCH 604/620] Try to fix build --- dnsapi/dns_unoeuro.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index 6b582ddd..8a1928de 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -67,7 +67,7 @@ dns_unoeuro_add() { else _info "Updating record" record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) - record_line_number=$(($record_line_number-1)) + record_line_number=$(($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" @@ -123,7 +123,7 @@ dns_unoeuro_rm() { _info "Don't need to remove." else record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) - record_line_number=$(($record_line_number-1)) + record_line_number=$(($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" From 3f1e6c128ff0d1af3fc1fc896f115821b55af885 Mon Sep 17 00:00:00 2001 From: Aarup Date: Fri, 8 Dec 2017 08:31:24 +0100 Subject: [PATCH 605/620] Try again --- dnsapi/dns_unoeuro.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index 8a1928de..be0fadbe 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -67,7 +67,7 @@ dns_unoeuro_add() { else _info "Updating record" record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) - record_line_number=$(($record_line_number - 1)) + record_line_number=$((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" @@ -123,7 +123,7 @@ dns_unoeuro_rm() { _info "Don't need to remove." else record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) - record_line_number=$(($record_line_number - 1)) + record_line_number=$((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" From ca7ebd933324db4c9ea4a383321413c6deb399f3 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 8 Dec 2017 19:49:18 +0800 Subject: [PATCH 606/620] fix typo --- acme.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 0755f78a..2affeb93 100755 --- a/acme.sh +++ b/acme.sh @@ -3081,8 +3081,7 @@ _regAccount() { regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' fi - if [ -z "$_updateTos" ]; then - _info "Registering account" + _info "Registering account" if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then _err "Register account Error: $response" From 4249e13eb4089deb518d0e54e10b8bd24d2f5640 Mon Sep 17 00:00:00 2001 From: neilpang Date: Fri, 8 Dec 2017 19:54:25 +0800 Subject: [PATCH 607/620] fix format --- acme.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 2affeb93..88273cf5 100755 --- a/acme.sh +++ b/acme.sh @@ -16,7 +16,6 @@ _SUB_FOLDERS="dnsapi deploy" _OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory" - DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" DEFAULT_ACCOUNT_EMAIL="" @@ -2199,7 +2198,7 @@ _initAPI() { ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_NEW_NONCE - + ACME_AGREEMENT=$(echo "$response" | _egrep_o 'terms-of-service" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_AGREEMENT From dbc3ad130461a4c9dde8b2ce778ae1881960508f Mon Sep 17 00:00:00 2001 From: Aarup Date: Fri, 8 Dec 2017 12:59:02 +0100 Subject: [PATCH 608/620] use _math --- dnsapi/dns_unoeuro.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index be0fadbe..1479d54d 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -67,7 +67,7 @@ dns_unoeuro_add() { else _info "Updating record" record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) - record_line_number=$((record_line_number - 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" @@ -123,7 +123,7 @@ dns_unoeuro_rm() { _info "Don't need to remove." else record_line_number=$(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1) - record_line_number=$((record_line_number - 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" From f763e1edd7c677e9d313288b8426223f86ca9e49 Mon Sep 17 00:00:00 2001 From: Aarup Date: Fri, 8 Dec 2017 13:20:25 +0100 Subject: [PATCH 609/620] fix contains usage --- dnsapi/dns_unoeuro.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index 1479d54d..f75de39e 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -114,12 +114,12 @@ dns_unoeuro_rm() { _debug "Getting txt records" _uno_rest GET "my/products/$h/dns/records" - if ! _contains "$response" "\"status\": 200" >/dev/null; then + if ! _contains "$response" "\"status\": 200"; then _err "Error" return 1 fi - if ! _contains "$response" "$_sub_domain" >/dev/null; then + 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) @@ -163,7 +163,7 @@ _get_root() { return 1 fi - if _contains "$response" "\"status\": 200" >/dev/null; then + if _contains "$response" "\"status\": 200"; then _domain_id=$h if [ "$_domain_id" ]; then _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) From f9b8d7a9d8316ad0e6b663572f552bb32a6236a4 Mon Sep 17 00:00:00 2001 From: Aarup Date: Fri, 8 Dec 2017 13:22:17 +0100 Subject: [PATCH 610/620] renamed uno_user and uno_key --- dnsapi/dns_unoeuro.sh | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/dnsapi/dns_unoeuro.sh b/dnsapi/dns_unoeuro.sh index f75de39e..a3803a21 100644 --- a/dnsapi/dns_unoeuro.sh +++ b/dnsapi/dns_unoeuro.sh @@ -1,9 +1,9 @@ #!/usr/bin/env sh # -#Uno_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +#UNO_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" # -#Uno_User="UExxxxxx" +#UNO_User="UExxxxxx" Uno_Api="https://api.unoeuro.com/1" @@ -14,25 +14,25 @@ dns_unoeuro_add() { fulldomain=$1 txtvalue=$2 - Uno_Key="${Uno_Key:-$(_readaccountconf_mutable Uno_Key)}" - Uno_User="${Uno_User:-$(_readaccountconf_mutable Uno_User)}" - if [ -z "$Uno_Key" ] || [ -z "$Uno_User" ]; then - Uno_Key="" - Uno_User="" + UNO_Key="${UNO_Key:-$(_readaccountconf_mutable UNO_Key)}" + UNO_User="${UNO_User:-$(_readaccountconf_mutable UNO_User)}" + if [ -z "$UNO_Key" ] || [ -z "$UNO_User" ]; then + UNO_Key="" + UNO_User="" _err "You haven't specified a UnoEuro api key and account yet." _err "Please create your key and try again." return 1 fi - if ! _contains "$Uno_User" "UE"; then - _err "It seems that the Uno_User=$Uno_User is not a valid username." + if ! _contains "$UNO_User" "UE"; then + _err "It seems that the UNO_User=$UNO_User is not a valid username." _err "Please check and retry." return 1 fi #save the api key and email to the account conf file. - _saveaccountconf_mutable Uno_Key "$Uno_Key" - _saveaccountconf_mutable Uno_User "$Uno_User" + _saveaccountconf_mutable UNO_Key "$UNO_Key" + _saveaccountconf_mutable UNO_User "$UNO_User" _debug "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -86,18 +86,18 @@ dns_unoeuro_rm() { fulldomain=$1 txtvalue=$2 - Uno_Key="${Uno_Key:-$(_readaccountconf_mutable Uno_Key)}" - Uno_User="${Uno_User:-$(_readaccountconf_mutable Uno_User)}" - if [ -z "$Uno_Key" ] || [ -z "$Uno_User" ]; then - Uno_Key="" - Uno_User="" + UNO_Key="${UNO_Key:-$(_readaccountconf_mutable UNO_Key)}" + UNO_User="${UNO_User:-$(_readaccountconf_mutable UNO_User)}" + if [ -z "$UNO_Key" ] || [ -z "$UNO_User" ]; then + UNO_Key="" + UNO_User="" _err "You haven't specified a UnoEuro api key and account yet." _err "Please create your key and try again." return 1 fi - if ! _contains "$Uno_User" "UE"; then - _err "It seems that the Uno_User=$Uno_User is not a valid username." + if ! _contains "$UNO_User" "UE"; then + _err "It seems that the UNO_User=$UNO_User is not a valid username." _err "Please check and retry." return 1 fi @@ -188,9 +188,9 @@ _uno_rest() { if [ "$m" != "GET" ]; then _debug data "$data" - response="$(_post "$data" "$Uno_Api/$Uno_User/$Uno_Key/$ep" "" "$m")" + response="$(_post "$data" "$Uno_Api/$UNO_User/$UNO_Key/$ep" "" "$m")" else - response="$(_get "$Uno_Api/$Uno_User/$Uno_Key/$ep")" + response="$(_get "$Uno_Api/$UNO_User/$UNO_Key/$ep")" fi if [ "$?" != "0" ]; then From fb6e0658cf23a79cf4c16a3898fd57d281be0a32 Mon Sep 17 00:00:00 2001 From: Aarup Date: Fri, 8 Dec 2017 14:09:04 +0100 Subject: [PATCH 611/620] update README --- dnsapi/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dnsapi/README.md b/dnsapi/README.md index 5fdcd849..8a486aee 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -607,8 +607,8 @@ Please report any issues to https://github.com/angel333/acme.sh or to Date: Sat, 9 Dec 2017 14:13:05 +0100 Subject: [PATCH 612/620] Fix shebang --- dnsapi/dns_inwx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index ae20074b..74440bd7 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -1,4 +1,4 @@ -#!/usr/local/bin/sh +#!/usr/bin/env sh # #INWX_User="username" From f7c346de0928fcc57eb0c8f7561fada69118022d Mon Sep 17 00:00:00 2001 From: speedmann Date: Sat, 9 Dec 2017 14:20:36 +0100 Subject: [PATCH 613/620] Fix order in README and add link to inwx.de and apidocs --- README.md | 2 +- dnsapi/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8420c02c..eb122917 100644 --- a/README.md +++ b/README.md @@ -339,8 +339,8 @@ You don't have to do anything manually! 1. Dyn Managed DNS API 1. Yandex PDD API (https://pdd.yandex.ru) 1. Hurricane Electric DNS service (https://dns.he.net) -1. INWX (https://www.inwx.de/) 1. UnoEuro API (https://www.unoeuro.com/) +1. INWX (https://www.inwx.de/) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index 11b6b3af..c16e7598 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -620,7 +620,7 @@ The `UNO_Key` and `UNO_User` will be saved in `~/.acme.sh/account.conf` and will ## 33. Use INWX -INWX offers an xmlrpc api with your standard login credentials, set them like so: +[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" From 8201458332ea5898177118097621dbac842ad64f Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 9 Dec 2017 21:50:45 +0800 Subject: [PATCH 614/620] fix https://github.com/Neilpang/acme.sh/issues/1123 --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 88273cf5..472975a6 100755 --- a/acme.sh +++ b/acme.sh @@ -4308,7 +4308,12 @@ _installcert() { if [ -f "$_real_key" ] && [ ! "$IS_RENEW" ]; then cp "$_real_key" "$_backup_path/key.bak" fi - cat "$CERT_KEY_PATH" >"$_real_key" + if [ -f "$_real_key" ]; then + cat "$CERT_KEY_PATH" >"$_real_key" + else + cat "$CERT_KEY_PATH" >"$_real_key" + chmod 700 "$_real_key" + fi fi if [ "$_real_fullchain" ]; then From ae29929714b8cb8e4b7c612a354b56433f8ac47c Mon Sep 17 00:00:00 2001 From: Jens Hartlep Date: Sat, 9 Dec 2017 19:32:53 +0100 Subject: [PATCH 615/620] added dns api for servercow --- dnsapi/README.md | 16 ++++ dnsapi/dns_servercow.sh | 170 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100755 dnsapi/dns_servercow.sh diff --git a/dnsapi/README.md b/dnsapi/README.md index c16e7598..d357c053 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -635,6 +635,22 @@ acme.sh --issue --dns dns_inwx -d example.com -d www.example.com The `INWX_User` and `INWX_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 34. User Servercow API v1 + +Create a new user from the servercow control center. Don't forget to activate **DNS API** for this user. + +``` +export SERVERCOW_API_Username=username +export SERVERCOW_API_Password=password +``` + +Now you cann issue a cert: + +``` +acme.sh --issue --dns dns_servercow -d example.com -d www.example.com +``` +Both, `SERVERCOW_API_Username` and `SERVERCOW_API_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_servercow.sh b/dnsapi/dns_servercow.sh new file mode 100755 index 00000000..e7049598 --- /dev/null +++ b/dnsapi/dns_servercow.sh @@ -0,0 +1,170 @@ +#!/usr/bin/env sh + +########## +# Custom servercow.de DNS API v1 for use with [acme.sh](https://github.com/Neilpang/acme.sh) +# +# Usage: +# export SERVERCOW_API_Username=username +# export SERVERCOW_API_Password=password +# acme.sh --issue -d example.com --dns dns_servercow +# +# Issues: +# Any issues / questions / suggestions can be posted here: +# https://github.com/jhartlep/servercow-dns-api/issues +# +# Author: Jens Hartlep +########## + +SERVERCOW_API="https://api.servercow.de/dns/v1/domains" + +# Usage dns_servercow_add _acme-challenge.www.domain.com "abcdefghijklmnopqrstuvwxyz" +dns_servercow_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Using servercow" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" + SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" + if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then + SERVERCOW_API_Username="" + SERVERCOW_API_Password="" + _err "You don't specify servercow api username and password yet." + _err "Please create your username and password and try again." + return 1 + fi + + # save the credentials to the account conf file + _saveaccountconf_mutable SERVERCOW_API_Username "$SERVERCOW_API_Username" + _saveaccountconf_mutable SERVERCOW_API_Password "$SERVERCOW_API_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; then + if printf -- "%s" "$response" | grep "ok" > /dev/null; then + _info "Added, OK" + return 0 + else + _err "add txt record error." + return 1 + fi + fi + _err "add txt record error." + + return 1 +} + +# Usage fulldomain txtvalue +# Remove the txt record after validation +dns_servercow_rm() { + fulldomain=$1 + txtvalue=$2 + + _info "Using servercow" + _debug fulldomain "$fulldomain" + _debug txtvalue "$fulldomain" + + SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" + SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" + if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then + SERVERCOW_API_Username="" + SERVERCOW_API_Password="" + _err "You don't specify servercow api username and password yet." + _err "Please create your username and password and try again." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then + if printf -- "%s" "$response" | grep "ok" > /dev/null; then + _info "Deleted, OK" + _contains "$response" '"message":"ok"' + else + _err "delete txt record error." + return 1 + fi + fi + +} + +#################### Private functions below ################################## + +# _acme-challenge.www.domain.com +# returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + fulldomain=$1 + i=2 + p=1 + + while true; do + _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + + _debug _domain "$_domain" + if [ -z "$_domain" ]; then + # not valid + return 1 + fi + + if ! _servercow_api GET "$_domain"; then + return 1 + fi + + if ! _contains "$response" '"error":"no such domain in user context"' > /dev/null; then + _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) + if [ -z "$_sub_domain" ]; then + # not valid + return 1 + fi + + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done; + + return 1 +} + +_servercow_api() { + method=$1 + domain=$2 + data="$3" + + export _H1="Content-Type: application/json" + export _H2="X-Auth-Username: $SERVERCOW_API_Username" + export _H3="X-Auth-Password: $SERVERCOW_API_Password" + + if [ "$method" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$SERVERCOW_API/$domain" "" "$method")" + else + response="$(_get "$SERVERCOW_API/$domain")" + fi + + if [ "$?" != "0" ]; then + _err "error $domain" + return 1 + fi + _debug2 response "$response" + return 0 +} From b140e2553bdfce40b99fb3ecd246ef3e64d33d42 Mon Sep 17 00:00:00 2001 From: Jens Hartlep Date: Sat, 9 Dec 2017 19:33:48 +0100 Subject: [PATCH 616/620] added Servercow to supported list --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb122917..5574b67a 100644 --- a/README.md +++ b/README.md @@ -341,7 +341,7 @@ You don't have to do anything manually! 1. Hurricane Electric DNS service (https://dns.he.net) 1. UnoEuro API (https://www.unoeuro.com/) 1. INWX (https://www.inwx.de/) - +1. Servercow (https://servercow.de) And: From 488745f3783e767adf5421b20ff96fc82aae9a37 Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 9 Dec 2017 20:05:05 +0100 Subject: [PATCH 617/620] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5574b67a..0d942757 100644 --- a/README.md +++ b/README.md @@ -343,6 +343,7 @@ You don't have to do anything manually! 1. INWX (https://www.inwx.de/) 1. Servercow (https://servercow.de) + And: 1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api From 1c9b19833cf0ebd0087f171f9f3f5cf24fc96ecc Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 9 Dec 2017 20:14:46 +0100 Subject: [PATCH 618/620] Update dns_servercow.sh replaced tab with space --- dnsapi/dns_servercow.sh | 260 ++++++++++++++++++++-------------------- 1 file changed, 130 insertions(+), 130 deletions(-) diff --git a/dnsapi/dns_servercow.sh b/dnsapi/dns_servercow.sh index e7049598..3ffc393e 100755 --- a/dnsapi/dns_servercow.sh +++ b/dnsapi/dns_servercow.sh @@ -19,88 +19,88 @@ SERVERCOW_API="https://api.servercow.de/dns/v1/domains" # Usage dns_servercow_add _acme-challenge.www.domain.com "abcdefghijklmnopqrstuvwxyz" dns_servercow_add() { - fulldomain=$1 - txtvalue=$2 - - _info "Using servercow" - _debug fulldomain "$fulldomain" - _debug txtvalue "$txtvalue" - - SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" - SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" - if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then - SERVERCOW_API_Username="" - SERVERCOW_API_Password="" - _err "You don't specify servercow api username and password yet." - _err "Please create your username and password and try again." - return 1 - fi - - # save the credentials to the account conf file - _saveaccountconf_mutable SERVERCOW_API_Username "$SERVERCOW_API_Username" - _saveaccountconf_mutable SERVERCOW_API_Password "$SERVERCOW_API_Password" - - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - _err "invalid domain" - return 1 - fi - - _debug _sub_domain "$_sub_domain" - _debug _domain "$_domain" - - if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; then - if printf -- "%s" "$response" | grep "ok" > /dev/null; then - _info "Added, OK" - return 0 - else - _err "add txt record error." - return 1 - fi - fi - _err "add txt record error." - - return 1 + fulldomain=$1 + txtvalue=$2 + + _info "Using servercow" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" + SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" + if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then + SERVERCOW_API_Username="" + SERVERCOW_API_Password="" + _err "You don't specify servercow api username and password yet." + _err "Please create your username and password and try again." + return 1 + fi + + # save the credentials to the account conf file + _saveaccountconf_mutable SERVERCOW_API_Username "$SERVERCOW_API_Username" + _saveaccountconf_mutable SERVERCOW_API_Password "$SERVERCOW_API_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; then + if printf -- "%s" "$response" | grep "ok" > /dev/null; then + _info "Added, OK" + return 0 + else + _err "add txt record error." + return 1 + fi + fi + _err "add txt record error." + + return 1 } # Usage fulldomain txtvalue # Remove the txt record after validation dns_servercow_rm() { - fulldomain=$1 - txtvalue=$2 - - _info "Using servercow" - _debug fulldomain "$fulldomain" - _debug txtvalue "$fulldomain" - - SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" - SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" - if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then - SERVERCOW_API_Username="" - SERVERCOW_API_Password="" - _err "You don't specify servercow api username and password yet." - _err "Please create your username and password and try again." - return 1 - fi - - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - _err "invalid domain" - return 1 - fi - - _debug _sub_domain "$_sub_domain" - _debug _domain "$_domain" - - if _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then - if printf -- "%s" "$response" | grep "ok" > /dev/null; then - _info "Deleted, OK" - _contains "$response" '"message":"ok"' - else - _err "delete txt record error." - return 1 - fi - fi + fulldomain=$1 + txtvalue=$2 + + _info "Using servercow" + _debug fulldomain "$fulldomain" + _debug txtvalue "$fulldomain" + + SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" + SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" + if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then + SERVERCOW_API_Username="" + SERVERCOW_API_Password="" + _err "You don't specify servercow api username and password yet." + _err "Please create your username and password and try again." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then + if printf -- "%s" "$response" | grep "ok" > /dev/null; then + _info "Deleted, OK" + _contains "$response" '"message":"ok"' + else + _err "delete txt record error." + return 1 + fi + fi } @@ -111,60 +111,60 @@ dns_servercow_rm() { # _sub_domain=_acme-challenge.www # _domain=domain.com _get_root() { - fulldomain=$1 - i=2 - p=1 - - while true; do - _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) - - _debug _domain "$_domain" - if [ -z "$_domain" ]; then - # not valid - return 1 - fi - - if ! _servercow_api GET "$_domain"; then - return 1 - fi - - if ! _contains "$response" '"error":"no such domain in user context"' > /dev/null; then - _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) - if [ -z "$_sub_domain" ]; then - # not valid - return 1 - fi - - return 0 - fi - - p=$i - i=$(_math "$i" + 1) - done; - - return 1 + fulldomain=$1 + i=2 + p=1 + + while true; do + _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + + _debug _domain "$_domain" + if [ -z "$_domain" ]; then + # not valid + return 1 + fi + + if ! _servercow_api GET "$_domain"; then + return 1 + fi + + if ! _contains "$response" '"error":"no such domain in user context"' > /dev/null; then + _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) + if [ -z "$_sub_domain" ]; then + # not valid + return 1 + fi + + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done; + + return 1 } _servercow_api() { - method=$1 - domain=$2 - data="$3" - - export _H1="Content-Type: application/json" - export _H2="X-Auth-Username: $SERVERCOW_API_Username" - export _H3="X-Auth-Password: $SERVERCOW_API_Password" - - if [ "$method" != "GET" ]; then - _debug data "$data" - response="$(_post "$data" "$SERVERCOW_API/$domain" "" "$method")" - else - response="$(_get "$SERVERCOW_API/$domain")" - fi - - if [ "$?" != "0" ]; then - _err "error $domain" - return 1 - fi - _debug2 response "$response" - return 0 + method=$1 + domain=$2 + data="$3" + + export _H1="Content-Type: application/json" + export _H2="X-Auth-Username: $SERVERCOW_API_Username" + export _H3="X-Auth-Password: $SERVERCOW_API_Password" + + if [ "$method" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$SERVERCOW_API/$domain" "" "$method")" + else + response="$(_get "$SERVERCOW_API/$domain")" + fi + + if [ "$?" != "0" ]; then + _err "error $domain" + return 1 + fi + _debug2 response "$response" + return 0 } From 8101aceab5dad0ac83c8446380d814d77f44fecf Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 9 Dec 2017 20:18:05 +0100 Subject: [PATCH 619/620] Update dns_servercow.sh fixed remaining issues from shellcheck --- dnsapi/dns_servercow.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_servercow.sh b/dnsapi/dns_servercow.sh index 3ffc393e..872ae58c 100755 --- a/dnsapi/dns_servercow.sh +++ b/dnsapi/dns_servercow.sh @@ -50,7 +50,7 @@ dns_servercow_add() { _debug _domain "$_domain" if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; then - if printf -- "%s" "$response" | grep "ok" > /dev/null; then + if printf -- "%s" "$response" | grep "ok" >/dev/null; then _info "Added, OK" return 0 else @@ -92,8 +92,8 @@ dns_servercow_rm() { _debug _sub_domain "$_sub_domain" _debug _domain "$_domain" - if _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then - if printf -- "%s" "$response" | grep "ok" > /dev/null; then + if _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then + if printf -- "%s" "$response" | grep "ok" >/dev/null; then _info "Deleted, OK" _contains "$response" '"message":"ok"' else @@ -140,7 +140,7 @@ _get_root() { p=$i i=$(_math "$i" + 1) - done; + done return 1 } From a95ccc7e4cecd7fa92144dc8af7bca5ffccb107a Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 9 Dec 2017 20:22:09 +0100 Subject: [PATCH 620/620] Update dns_servercow.sh ... didn't see this line in spellcheck ... :S --- dnsapi/dns_servercow.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_servercow.sh b/dnsapi/dns_servercow.sh index 872ae58c..be4e59da 100755 --- a/dnsapi/dns_servercow.sh +++ b/dnsapi/dns_servercow.sh @@ -128,7 +128,7 @@ _get_root() { return 1 fi - if ! _contains "$response" '"error":"no such domain in user context"' > /dev/null; then + if ! _contains "$response" '"error":"no such domain in user context"' >/dev/null; then _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) if [ -z "$_sub_domain" ]; then # not valid