From 1f4e64f81d7650e7811153cf73e527b94fc252c1 Mon Sep 17 00:00:00 2001
From: neilpang <github@byneil.com>
Date: Tue, 4 Apr 2017 00:21:39 +0800
Subject: [PATCH 01/18] 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" "<IsTruncated>true</IsTruncated>" && _contains "$response"  "<NextMarker>"; then
+          _debug "IsTruncated"
+          _nextMarker="$(echo "$response" | _egrep_o "<NextMarker>.*</NextMarker>" | 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 fc9649dbc48bc89626d0f80fd7db20442cb17f0e Mon Sep 17 00:00:00 2001
From: neilpang <github@byneil.com>
Date: Tue, 4 Apr 2017 10:02:45 +0800
Subject: [PATCH 02/18] 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 "<NextMarker>.*</NextMarker>" | 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 fd77e463a150e2253aa7ca6658c17bddb62fef79 Mon Sep 17 00:00:00 2001
From: neilpang <github@byneil.com>
Date: Tue, 4 Apr 2017 14:34:23 +0800
Subject: [PATCH 03/18] 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 <github@byneil.com>
Date: Tue, 4 Apr 2017 15:54:45 +0800
Subject: [PATCH 04/18] 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" "<IsTruncated>true</IsTruncated>" && _contains "$response"  "<NextMarker>"; then
+        if _contains "$response" "<IsTruncated>true</IsTruncated>" && _contains "$response" "<NextMarker>"; then
           _debug "IsTruncated"
           _nextMarker="$(echo "$response" | _egrep_o "<NextMarker>.*</NextMarker>" | cut -d '>' -f 2 | cut -d '<' -f 1)"
           _debug "NextMarker" "$_nextMarker"

From 7df062b7d7d9ff95f6a3b58f005431ccd3cd4ec8 Mon Sep 17 00:00:00 2001
From: neilpang <github@byneil.com>
Date: Tue, 4 Apr 2017 22:33:26 +0800
Subject: [PATCH 05/18] 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 <github@byneil.com>
Date: Wed, 5 Apr 2017 20:46:17 +0800
Subject: [PATCH 06/18] 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 <github@byneil.com>
Date: Wed, 5 Apr 2017 20:54:53 +0800
Subject: [PATCH 07/18] 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 <github@byneil.com>
Date: Thu, 6 Apr 2017 19:29:09 +0800
Subject: [PATCH 08/18] 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 <lks@gidcs.net>
Date: Sat, 8 Apr 2017 14:50:39 +0800
Subject: [PATCH 09/18] 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 <github@byneil.com>
Date: Tue, 11 Apr 2017 21:37:56 +0800
Subject: [PATCH 10/18] 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 <github@byneil.com>
Date: Tue, 11 Apr 2017 22:29:49 +0800
Subject: [PATCH 11/18] 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 cd98951001ca5f9bbd79a6e35bca3653b1b1e0d8 Mon Sep 17 00:00:00 2001
From: neilpang <github@byneil.com>
Date: Sun, 16 Apr 2017 09:36:59 +0800
Subject: [PATCH 12/18] 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 <github@byneil.com>
Date: Sun, 16 Apr 2017 11:16:48 +0800
Subject: [PATCH 13/18] 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 <github@byneil.com>
Date: Mon, 17 Apr 2017 19:08:34 +0800
Subject: [PATCH 14/18] 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 '</\?TABLE\|</\?TD\|</\?TR\|</\?TH' \
       | sed 's/^[\ \t]*//g' \
@@ -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 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
diff --git a/dnsapi/dns_ovh.sh b/dnsapi/dns_ovh.sh
index 71642bd4..18f9c7dc 100755
--- a/dnsapi/dns_ovh.sh
+++ b/dnsapi/dns_ovh.sh
@@ -14,7 +14,7 @@
 #'ovh-eu'
 OVH_EU='https://eu.api.ovh.com/1.0'
 
-#'ovh-ca': 
+#'ovh-ca':
 OVH_CA='https://ca.api.ovh.com/1.0'
 
 #'kimsufi-eu'

From 9be2c1beb978afde98b4ecdad521e47d636751c5 Mon Sep 17 00:00:00 2001
From: neilpang <github@byneil.com>
Date: Wed, 19 Apr 2017 23:12:37 +0800
Subject: [PATCH 15/18] 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 <lav451@gmail.com>
Date: Sat, 15 Apr 2017 14:34:37 +0300
Subject: [PATCH 16/18] 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 <loal@gurtam.com>
Date: Fri, 21 Apr 2017 12:30:01 +0300
Subject: [PATCH 17/18] 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 <loal@gurtam.com>
Date: Fri, 21 Apr 2017 13:15:39 +0300
Subject: [PATCH 18/18] 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/).