Browse Source

Merge branch 'master' of github.com:Neilpang/acme.sh

Ivar Larsson 7 years ago
parent
commit
50dee5d464
13 changed files with 253 additions and 86 deletions
  1. 6 2
      README.md
  2. 53 17
      acme.sh
  3. 0 6
      deploy/keychain.sh
  4. 19 3
      dnsapi/README.md
  5. 6 2
      dnsapi/dns_azure.sh
  6. 4 4
      dnsapi/dns_cf.sh
  7. 25 5
      dnsapi/dns_dgon.sh
  8. 18 35
      dnsapi/dns_dnsimple.sh
  9. 1 1
      dnsapi/dns_freedns.sh
  10. 1 1
      dnsapi/dns_he.sh
  11. 107 0
      dnsapi/dns_kinghost.sh
  12. 10 7
      dnsapi/dns_pdns.sh
  13. 3 3
      dnsapi/dns_yandex.sh

+ 6 - 2
README.md

@@ -37,6 +37,8 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
 - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297)
 - [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297)
 - [archlinux](https://aur.archlinux.org/packages/acme.sh-git/)
 - [archlinux](https://aur.archlinux.org/packages/acme.sh-git/)
 - [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient)
 - [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient)
+- [CentOS Web Panel](http://centos-webpanel.com/)
+- [lnmp.org](https://lnmp.org/)
 - [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials)
 - [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials)
 
 
 # Tested OS
 # Tested OS
@@ -313,9 +315,9 @@ You don't have to do anything manually!
 1. zonomi.com DNS API
 1. zonomi.com DNS API
 1. DreamHost.com API
 1. DreamHost.com API
 1. DirectAdmin API
 1. DirectAdmin API
+1. KingHost (https://www.kinghost.com.br/)
 1. Loopia.se API
 1. Loopia.se API
 
 
-
 And: 
 And: 
 
 
 **lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
 **lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
@@ -330,6 +332,8 @@ For more details: [How to use DNS API](dnsapi)
 
 
 # 8. Use DNS manual mode:
 # 8. Use DNS manual mode:
 
 
+See: https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode first.
+
 If your dns provider doesn't support any api access, you can add the txt record by your hand.
 If your dns provider doesn't support any api access, you can add the txt record by your hand.
 
 
 ```bash
 ```bash
@@ -399,7 +403,7 @@ Valid values are:
 It's simple, just give a wildcard domain as the `-d` parameter.
 It's simple, just give a wildcard domain as the `-d` parameter.
 
 
 ```sh
 ```sh
-acme.sh  --issue -d example.com  -d *.example.com  --dns dns_cf
+acme.sh  --issue -d example.com  -d '*.example.com'  --dns dns_cf
 ```
 ```
 
 
 
 

+ 53 - 17
acme.sh

@@ -110,10 +110,14 @@ _STATELESS_WIKI="https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode"
 
 
 _DNS_ALIAS_WIKI="https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode"
 _DNS_ALIAS_WIKI="https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode"
 
 
+_DNS_MANUAL_WIKI="https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode"
+
 _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_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"
 _DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR"
 
 
+_DNS_MANUAL_ERROR="It seems that you are using dns manual mode. Read this link first: $_DNS_MANUAL_WIKI"
+
 __INTERACTIVE=""
 __INTERACTIVE=""
 if [ -t 1 ]; then
 if [ -t 1 ]; then
   __INTERACTIVE="1"
   __INTERACTIVE="1"
@@ -1617,6 +1621,7 @@ _post() {
   _debug $httpmethod
   _debug $httpmethod
   _debug "_post_url" "$_post_url"
   _debug "_post_url" "$_post_url"
   _debug2 "body" "$body"
   _debug2 "body" "$body"
+  _debug2 "_postContentType" "$_postContentType"
 
 
   _inithttp
   _inithttp
 
 
@@ -1625,14 +1630,19 @@ _post() {
     if [ "$HTTPS_INSECURE" ]; then
     if [ "$HTTPS_INSECURE" ]; then
       _CURL="$_CURL --insecure  "
       _CURL="$_CURL --insecure  "
     fi
     fi
-    if [ "$_postContentType" ]; then
-      _CURL="$_CURL -H \"Content-Type: $_postContentType\" "
-    fi
     _debug "_CURL" "$_CURL"
     _debug "_CURL" "$_CURL"
     if [ "$needbase64" ]; then
     if [ "$needbase64" ]; then
-      response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
+      if [ "$_postContentType" ]; then
+        response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
+      else
+        response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
+      fi
     else
     else
-      response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
+      if [ "$_postContentType" ]; then
+        response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
+      else
+        response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
+      fi
     fi
     fi
     _ret="$?"
     _ret="$?"
     if [ "$_ret" != "0" ]; then
     if [ "$_ret" != "0" ]; then
@@ -1785,19 +1795,25 @@ _send_signed_request() {
     return 1
     return 1
   fi
   fi
 
 
+  if [ "$ACME_VERSION" = "2" ]; then
+    __request_conent_type="$CONTENT_TYPE_JSON"
+  else
+    __request_conent_type=""
+  fi
   payload64=$(printf "%s" "$payload" | _base64 | _url_replace)
   payload64=$(printf "%s" "$payload" | _base64 | _url_replace)
   _debug3 payload64 "$payload64"
   _debug3 payload64 "$payload64"
 
 
   MAX_REQUEST_RETRY_TIMES=5
   MAX_REQUEST_RETRY_TIMES=5
   _request_retry_times=0
   _request_retry_times=0
   while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do
   while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do
+    _request_retry_times=$(_math "$_request_retry_times" + 1)
     _debug3 _request_retry_times "$_request_retry_times"
     _debug3 _request_retry_times "$_request_retry_times"
     if [ -z "$_CACHED_NONCE" ]; then
     if [ -z "$_CACHED_NONCE" ]; then
       _headers=""
       _headers=""
       if [ "$ACME_NEW_NONCE" ]; then
       if [ "$ACME_NEW_NONCE" ]; then
         _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE"
         _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE"
         nonceurl="$ACME_NEW_NONCE"
         nonceurl="$ACME_NEW_NONCE"
-        if _post "" "$nonceurl" "" "HEAD" "$CONTENT_TYPE_JSON"; then
+        if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type"; then
           _headers="$(cat "$HTTP_HEADER")"
           _headers="$(cat "$HTTP_HEADER")"
         fi
         fi
       fi
       fi
@@ -1821,7 +1837,11 @@ _send_signed_request() {
     fi
     fi
     nonce="$_CACHED_NONCE"
     nonce="$_CACHED_NONCE"
     _debug2 nonce "$nonce"
     _debug2 nonce "$nonce"
-
+    if [ -z "$nonce" ]; then
+      _info "Could not get nonce, let's try again."
+      _sleep 2
+      continue
+    fi
     if [ "$ACME_VERSION" = "2" ]; then
     if [ "$ACME_VERSION" = "2" ]; then
       if [ "$url" = "$ACME_NEW_ACCOUNT" ] || [ "$url" = "$ACME_REVOKE_CERT" ]; then
       if [ "$url" = "$ACME_NEW_ACCOUNT" ] || [ "$url" = "$ACME_REVOKE_CERT" ]; then
         protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}'
         protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}'
@@ -1852,7 +1872,7 @@ _send_signed_request() {
     fi
     fi
     _debug3 body "$body"
     _debug3 body "$body"
 
 
-    response="$(_post "$body" "$url" "$needbase64" "POST" "$CONTENT_TYPE_JSON")"
+    response="$(_post "$body" "$url" "$needbase64" "POST" "$__request_conent_type")"
     _CACHED_NONCE=""
     _CACHED_NONCE=""
 
 
     if [ "$?" != "0" ]; then
     if [ "$?" != "0" ]; then
@@ -1879,7 +1899,6 @@ _send_signed_request() {
 
 
     if _contains "$_body" "JWS has invalid anti-replay nonce"; then
     if _contains "$_body" "JWS has invalid anti-replay nonce"; then
       _info "It seems the CA server is busy now, let's wait and retry."
       _info "It seems the CA server is busy now, let's wait and retry."
-      _request_retry_times=$(_math "$_request_retry_times" + 1)
       _sleep 5
       _sleep 5
       continue
       continue
     fi
     fi
@@ -3247,10 +3266,16 @@ _regAccount() {
     return 1
     return 1
   fi
   fi
 
 
+  _debug2 responseHeaders "$responseHeaders"
   _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
   _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
   _debug "_accUri" "$_accUri"
   _debug "_accUri" "$_accUri"
+  if [ -z "$_accUri" ]; then
+    _err "Can not find account id url."
+    _err "$responseHeaders"
+    return 1
+  fi
   _savecaconf "ACCOUNT_URL" "$_accUri"
   _savecaconf "ACCOUNT_URL" "$_accUri"
-  export ACCOUNT_URL="$ACCOUNT_URL"
+  export ACCOUNT_URL="$_accUri"
 
 
   CA_KEY_HASH="$(__calcAccountKeyHash)"
   CA_KEY_HASH="$(__calcAccountKeyHash)"
   _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH"
   _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH"
@@ -3460,6 +3485,11 @@ issue() {
     mkdir -p "$DOMAIN_PATH"
     mkdir -p "$DOMAIN_PATH"
   fi
   fi
 
 
+  if _hasfield "$_web_roots" "$W_DNS" && [ -z "$FORCE_DNS_MANUAL" ]; then
+    _err "$_DNS_MANUAL_ERROR"
+    return 1
+  fi
+
   _debug "Using ACME_DIRECTORY: $ACME_DIRECTORY"
   _debug "Using ACME_DIRECTORY: $ACME_DIRECTORY"
 
 
   _initAPI
   _initAPI
@@ -3521,7 +3551,7 @@ issue() {
   _saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")"
   _saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")"
   _debug2 _saved_account_key_hash "$_saved_account_key_hash"
   _debug2 _saved_account_key_hash "$_saved_account_key_hash"
 
 
-  if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then
+  if [ -z "$ACCOUNT_URL" ] || [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then
     if ! _regAccount "$_accountkeylength"; then
     if ! _regAccount "$_accountkeylength"; then
       _on_issue_err "$_post_hook"
       _on_issue_err "$_post_hook"
       return 1
       return 1
@@ -3819,7 +3849,7 @@ $_authorizations_map"
     if [ "$dnsadded" = '0' ]; then
     if [ "$dnsadded" = '0' ]; then
       _savedomainconf "Le_Vlist" "$vlist"
       _savedomainconf "Le_Vlist" "$vlist"
       _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit."
       _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."
+      _err "Please add the TXT records to the domains, and re-run with --renew."
       _clearup
       _clearup
       _on_issue_err "$_post_hook"
       _on_issue_err "$_post_hook"
       return 1
       return 1
@@ -4083,13 +4113,15 @@ $_authorizations_map"
     fi
     fi
     if [ "$code" != "200" ]; then
     if [ "$code" != "200" ]; then
       _err "Sign failed, code is not 200."
       _err "Sign failed, code is not 200."
+      _err "$response"
       _on_issue_err "$_post_hook"
       _on_issue_err "$_post_hook"
       return 1
       return 1
     fi
     fi
     Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)"
     Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)"
 
 
     if ! _get "$Le_LinkCert" >"$CERT_PATH"; then
     if ! _get "$Le_LinkCert" >"$CERT_PATH"; then
-      _err "Sign failed, code is not 200."
+      _err "Sign failed, can not download cert:$Le_LinkCert."
+      _err "$response"
       _on_issue_err "$_post_hook"
       _on_issue_err "$_post_hook"
       return 1
       return 1
     fi
     fi
@@ -4105,12 +4137,12 @@ $_authorizations_map"
     fi
     fi
   else
   else
     if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then
     if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then
-      _err "Sign failed."
+      _err "Sign failed. $response"
       _on_issue_err "$_post_hook"
       _on_issue_err "$_post_hook"
       return 1
       return 1
     fi
     fi
     _rcert="$response"
     _rcert="$response"
-    Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
+    Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
     echo "$BEGIN_CERT" >"$CERT_PATH"
     echo "$BEGIN_CERT" >"$CERT_PATH"
 
 
     #if ! _get "$Le_LinkCert" | _base64 "multiline"  >> "$CERT_PATH" ; then
     #if ! _get "$Le_LinkCert" | _base64 "multiline"  >> "$CERT_PATH" ; then
@@ -5456,8 +5488,8 @@ Parameters:
   --cert-home                       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.
   --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.
   --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.
+  --accountemail                    Specifies the account email, only valid for the '--install' and '--update-account' command.
+  --accountkey                      Specifies the account key path, only valid for the '--install' command.
   --days                            Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days.
   --days                            Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days.
   --httpport                        Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer.
   --httpport                        Specifies the standalone 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.
   --local-address                   Specifies the standalone/tls server listening address, in case you have multiple ip addresses.
@@ -5481,6 +5513,7 @@ Parameters:
   --listen-v6                       Force standalone/tls server to listen at ipv6.
   --listen-v6                       Force standalone/tls server to listen at ipv6.
   --openssl-bin                     Specifies a custom openssl bin location.
   --openssl-bin                     Specifies a custom openssl bin location.
   --use-wget                        Force to use wget, if you have both curl and wget installed.
   --use-wget                        Force to use wget, if you have both curl and wget installed.
+  --yes-I-know-dns-manual-mode-enough-go-ahead-please  Force to use dns manual mode: $_DNS_MANUAL_WIKI
   "
   "
 }
 }
 
 
@@ -5969,6 +6002,9 @@ _process() {
           shift
           shift
         fi
         fi
         ;;
         ;;
+      --yes-I-know-dns-manual-mode-enough-go-ahead-please)
+        export FORCE_DNS_MANUAL=1
+        ;;
       --log | --logfile)
       --log | --logfile)
         _log="1"
         _log="1"
         _logfile="$2"
         _logfile="$2"

+ 0 - 6
deploy/keychain.sh

@@ -1,11 +1,5 @@
 #!/usr/bin/env sh
 #!/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 #####################
 ########  Public functions #####################
 
 
 #domain keyfile certfile cafile fullchain
 #domain keyfile certfile cafile fullchain

+ 19 - 3
dnsapi/README.md

@@ -325,6 +325,8 @@ The `CY_Username`, `CY_Password` and `CY_OTP_Secret` will be saved in `~/.acme.s
 
 
 ## 17. Use Domain-Offensive/Resellerinterface/Domainrobot API
 ## 17. Use Domain-Offensive/Resellerinterface/Domainrobot API
 
 
+ATTENTION: You need to be a registered Reseller to be able to use the ResellerInterface. As a normal user you can not use this method.
+
 You will need your login credentials (Partner ID+Password) to the Resellerinterface, and export them before you run `acme.sh`:
 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_PID="KD-1234567"
@@ -525,8 +527,9 @@ For issues, please report to https://github.com/raidenii/acme.sh/issues.
 
 
 ## 28. 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.
+Create your API token here: https://www.name.com/account/settings/api
+
+Note: `Namecom_Username` should be your Name.com username and not the token name.  If you accidentally run the script with the token name as the username see `~/.acme.sh/account.conf` to fix the issue
 
 
 ```
 ```
 export Namecom_Username="testuser"
 export Namecom_Username="testuser"
@@ -784,7 +787,19 @@ acme.sh --issue --dns dns_da -d example.com -d www.example.com
 
 
 The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 
 
-## 42. Use Loopia.se API
+## 42. Use KingHost DNS API
+
+API access must be enabled at https://painel.kinghost.com.br/painel.api.php
+
+```
+export KINGHOST_Username="yourusername"
+export KINGHOST_Password="yourpassword"
+acme.sh --issue --dns dns_kinghost -d example.com -d *.example.com
+```
+
+The `KINGHOST_username` and `KINGHOST_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
+
+## 43. Use Loopia.se API
 User must provide login credentials to the Loopia API.
 User must provide login credentials to the Loopia API.
 The user needs the following permissions:
 The user needs the following permissions:
 
 
@@ -806,6 +821,7 @@ acme.sh --issue --dns dns_loopia -d example.com -d *.example.com
 
 
 The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
 
 
+=======
 
 
 # Use custom API
 # Use custom API
 
 

+ 6 - 2
dnsapi/dns_azure.sh

@@ -99,6 +99,7 @@ dns_azure_add() {
   _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken"
   _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken"
   if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then
   if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then
     _info "validation value added"
     _info "validation value added"
+    return 0
   else
   else
     _err "error adding validation value ($_code)"
     _err "error adding validation value ($_code)"
     return 1
     return 1
@@ -194,6 +195,7 @@ dns_azure_rm() {
       _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken"
       _azure_rest PUT "$acmeRecordURI" "$body" "$accesstoken"
       if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then
       if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then
         _info "validation value removed"
         _info "validation value removed"
+        return 0
       else
       else
         _err "error removing validation value ($_code)"
         _err "error removing validation value ($_code)"
         return 1
         return 1
@@ -226,6 +228,7 @@ _azure_rest() {
     else
     else
       response="$(_get "$ep")"
       response="$(_get "$ep")"
     fi
     fi
+    _ret="$?"
     _secure_debug2 "response $response"
     _secure_debug2 "response $response"
     _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")"
     _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")"
     _debug "http response code $_code"
     _debug "http response code $_code"
@@ -236,7 +239,7 @@ _azure_rest() {
       return 1
       return 1
     fi
     fi
     # See https://docs.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes
     # See https://docs.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes
-    if [ "$?" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then
+    if [ "$_ret" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then
       _request_retry_times="$(_math "$_request_retry_times" + 1)"
       _request_retry_times="$(_math "$_request_retry_times" + 1)"
       _info "REST call error $_code retrying $ep in $_request_retry_times s"
       _info "REST call error $_code retrying $ep in $_request_retry_times s"
       _sleep "$_request_retry_times"
       _sleep "$_request_retry_times"
@@ -281,6 +284,7 @@ _azure_getaccess_token() {
   body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials"
   body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials"
   _secure_debug2 "data $body"
   _secure_debug2 "data $body"
   response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")"
   response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")"
+  _ret="$?"
   _secure_debug2 "response $response"
   _secure_debug2 "response $response"
   response="$(echo "$response" | _normalizeJson)"
   response="$(echo "$response" | _normalizeJson)"
   accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
   accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
@@ -290,7 +294,7 @@ _azure_getaccess_token() {
     _err "no acccess token received. Check your Azure settings see $WIKI"
     _err "no acccess token received. Check your Azure settings see $WIKI"
     return 1
     return 1
   fi
   fi
-  if [ "$?" != "0" ]; then
+  if [ "$_ret" != "0" ]; then
     _err "error $response"
     _err "error $response"
     return 1
     return 1
   fi
   fi

+ 4 - 4
dnsapi/dns_cf.sh

@@ -19,8 +19,8 @@ dns_cf_add() {
   if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
   if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
     CF_Key=""
     CF_Key=""
     CF_Email=""
     CF_Email=""
-    _err "You don't specify cloudflare api key and email yet."
-    _err "Please create you key and try again."
+    _err "You didn't specify a cloudflare api key and email yet."
+    _err "Please create the key and try again."
     return 1
     return 1
   fi
   fi
 
 
@@ -94,8 +94,8 @@ dns_cf_rm() {
   if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
   if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
     CF_Key=""
     CF_Key=""
     CF_Email=""
     CF_Email=""
-    _err "You don't specify cloudflare api key and email yet."
-    _err "Please create you key and try again."
+    _err "You didn't specify a cloudflare api key and email yet."
+    _err "Please create the key and try again."
     return 1
     return 1
   fi
   fi
 
 

+ 25 - 5
dnsapi/dns_dgon.sh

@@ -20,12 +20,22 @@
 dns_dgon_add() {
 dns_dgon_add() {
   fulldomain="$(echo "$1" | _lower_case)"
   fulldomain="$(echo "$1" | _lower_case)"
   txtvalue=$2
   txtvalue=$2
+
+  DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}"
+  # Check if API Key Exist
+  if [ -z "$DO_API_KEY" ]; then
+    DO_API_KEY=""
+    _err "You did not specify DigitalOcean API key."
+    _err "Please export DO_API_KEY and try again."
+    return 1
+  fi
+
   _info "Using digitalocean dns validation - add record"
   _info "Using digitalocean dns validation - add record"
   _debug fulldomain "$fulldomain"
   _debug fulldomain "$fulldomain"
   _debug txtvalue "$txtvalue"
   _debug txtvalue "$txtvalue"
 
 
   ## save the env vars (key and domain split location) for later automated use
   ## save the env vars (key and domain split location) for later automated use
-  _saveaccountconf DO_API_KEY "$DO_API_KEY"
+  _saveaccountconf_mutable DO_API_KEY "$DO_API_KEY"
 
 
   ## split the domain for DO API
   ## split the domain for DO API
   if ! _get_base_domain "$fulldomain"; then
   if ! _get_base_domain "$fulldomain"; then
@@ -39,7 +49,7 @@ dns_dgon_add() {
   export _H1="Content-Type: application/json"
   export _H1="Content-Type: application/json"
   export _H2="Authorization: Bearer $DO_API_KEY"
   export _H2="Authorization: Bearer $DO_API_KEY"
   PURL='https://api.digitalocean.com/v2/domains/'$_domain'/records'
   PURL='https://api.digitalocean.com/v2/domains/'$_domain'/records'
-  PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'"}'
+  PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'","ttl":120}'
 
 
   _debug PURL "$PURL"
   _debug PURL "$PURL"
   _debug PBODY "$PBODY"
   _debug PBODY "$PBODY"
@@ -65,6 +75,16 @@ dns_dgon_add() {
 dns_dgon_rm() {
 dns_dgon_rm() {
   fulldomain="$(echo "$1" | _lower_case)"
   fulldomain="$(echo "$1" | _lower_case)"
   txtvalue=$2
   txtvalue=$2
+
+  DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}"
+  # Check if API Key Exist
+  if [ -z "$DO_API_KEY" ]; then
+    DO_API_KEY=""
+    _err "You did not specify DigitalOcean API key."
+    _err "Please export DO_API_KEY and try again."
+    return 1
+  fi
+
   _info "Using digitalocean dns validation - remove record"
   _info "Using digitalocean dns validation - remove record"
   _debug fulldomain "$fulldomain"
   _debug fulldomain "$fulldomain"
   _debug txtvalue "$txtvalue"
   _debug txtvalue "$txtvalue"
@@ -92,11 +112,11 @@ dns_dgon_rm() {
     domain_list="$(_get "$GURL")"
     domain_list="$(_get "$GURL")"
     ## 2) find record
     ## 2) find record
     ## check for what we are looing for: "type":"A","name":"$_sub_domain"
     ## 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\"")"
+    record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*[0-9]+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")"
     ## 3) check record and get next page
     ## 3) check record and get next page
     if [ -z "$record" ]; then
     if [ -z "$record" ]; then
       ## find the next page if we dont have a match
       ## 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+")"
+      nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")"
       if [ -z "$nextpage" ]; then
       if [ -z "$nextpage" ]; then
         _err "no record and no nextpage in digital ocean DNS removal"
         _err "no record and no nextpage in digital ocean DNS removal"
         return 1
         return 1
@@ -108,7 +128,7 @@ dns_dgon_rm() {
   done
   done
 
 
   ## we found the record
   ## we found the record
-  rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*\d+" | _egrep_o "\d+")"
+  rec_id="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
   _debug rec_id "$rec_id"
   _debug rec_id "$rec_id"
 
 
   ## delete the record
   ## delete the record

+ 18 - 35
dnsapi/dns_dnsimple.sh

@@ -39,34 +39,17 @@ dns_dnsimple_add() {
 
 
   _get_records "$_account_id" "$_domain" "$_sub_domain"
   _get_records "$_account_id" "$_domain" "$_sub_domain"
 
 
-  if [ "$_records_count" = "0" ]; then
-    _info "Adding record"
-    if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
-      if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then
-        _info "Added"
-        return 0
-      else
-        _err "Unexpected response while adding text record."
-        return 1
-      fi
-    fi
-    _err "Add txt record error."
-  else
-    _info "Updating record"
-    _extract_record_id "$_records" "$_sub_domain"
-
-    if _dnsimple_rest \
-      PATCH \
-      "$_account_id/zones/$_domain/records/$_record_id" \
-      "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
-
-      _info "Updated!"
+  _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
       return 0
+    else
+      _err "Unexpected response while adding text record."
+      return 1
     fi
     fi
-
-    _err "Update error"
-    return 1
   fi
   fi
+  _err "Add txt record error."
 }
 }
 
 
 # fulldomain
 # fulldomain
@@ -84,19 +67,19 @@ dns_dnsimple_rm() {
   fi
   fi
 
 
   _get_records "$_account_id" "$_domain" "$_sub_domain"
   _get_records "$_account_id" "$_domain" "$_sub_domain"
-  _extract_record_id "$_records" "$_sub_domain"
 
 
+  _extract_record_id "$_records" "$_sub_domain"
   if [ "$_record_id" ]; then
   if [ "$_record_id" ]; then
-
-    if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$_record_id"; then
-      _info "removed record" "$_record_id"
-      return 0
-    fi
+    echo "$_record_id" | while read -r item; do
+      if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$item"; then
+        _info "removed record" "$item"
+        return 0
+      else
+        _err "failed to remove record" "$item"
+        return 1
+      fi
+    done
   fi
   fi
-
-  _err "failed to remove record" "$_record_id"
-  return 1
-
 }
 }
 
 
 ####################  Private functions bellow ##################################
 ####################  Private functions bellow ##################################

+ 1 - 1
dnsapi/dns_freedns.sh

@@ -279,7 +279,7 @@ _freedns_add_txt_record() {
   domain_id="$2"
   domain_id="$2"
   subdomain="$3"
   subdomain="$3"
   value="$(printf '%s' "$4" | _url_encode)"
   value="$(printf '%s' "$4" | _url_encode)"
-  url="http://freedns.afraid.org/subdomain/save.php?step=2"
+  url="https://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")"
   htmlpage="$(_post "type=TXT&domain_id=$domain_id&subdomain=$subdomain&address=%22$value%22&send=Save%21" "$url")"
 
 

+ 1 - 1
dnsapi/dns_he.sh

@@ -143,7 +143,7 @@ _find_zone() {
 
 
     _debug "Looking for zone \"${_attempted_zone}\""
     _debug "Looking for zone \"${_attempted_zone}\""
 
 
-    line_num="$(echo "$_zone_names" | grep -n "$_attempted_zone" | cut -d : -f 1)"
+    line_num="$(echo "$_zone_names" | grep -n "^$_attempted_zone" | cut -d : -f 1)"
 
 
     if [ "$line_num" ]; then
     if [ "$line_num" ]; then
       _zone_id=$(echo "$_zone_ids" | sed -n "${line_num}p")
       _zone_id=$(echo "$_zone_ids" | sed -n "${line_num}p")

+ 107 - 0
dnsapi/dns_kinghost.sh

@@ -0,0 +1,107 @@
+#!/usr/bin/env sh
+
+############################################################
+# KingHost API support                                     #
+# http://api.kinghost.net/doc/                             #
+#                                                          #
+# Author: Felipe Keller Braz <felipebraz@kinghost.com.br>  #
+# Report Bugs here: https://github.com/kinghost/acme.sh    #
+#                                                          #
+# Values to export:                                        #
+# export KINGHOST_Username="email@provider.com"            #
+# export KINGHOST_Password="xxxxxxxxxx"                    #
+############################################################
+
+KING_Api="https://api.kinghost.net/acme"
+
+# Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
+# Used to add txt record
+dns_kinghost_add() {
+  fulldomain=$1
+  txtvalue=$2
+
+  KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}"
+  KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}"
+  if [ -z "$KINGHOST_Username" ] || [ -z "$KINGHOST_Password" ]; then
+    KINGHOST_Username=""
+    KINGHOST_Password=""
+    _err "You don't specify KingHost api password and email yet."
+    _err "Please create you key and try again."
+    return 1
+  fi
+
+  #save the credentials to the account conf file.
+  _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username"
+  _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password"
+
+  _debug "Getting txt records"
+  _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue"
+
+  #This API call returns "status":"ok" if dns record does not exists
+  #We are creating a new txt record here, so we expect the "ok" status
+  if ! echo "$response" | grep '"status":"ok"' >/dev/null; then
+    _err "Error"
+    _err "$response"
+    return 1
+  fi
+
+  _kinghost_rest POST "dns" "name=$fulldomain&content=$txtvalue"
+  if ! echo "$response" | grep '"status":"ok"' >/dev/null; then
+    _err "Error"
+    _err "$response"
+    return 1
+  fi
+
+  return 0
+}
+
+# Usage: fulldomain txtvalue
+# Used to remove the txt record after validation
+dns_kinghost_rm() {
+  fulldomain=$1
+  txtvalue=$2
+
+  KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}"
+  KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}"
+  if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_Username" ]; then
+    KINGHOST_Password=""
+    KINGHOST_Username=""
+    _err "You don't specify KingHost api key and email yet."
+    _err "Please create you key and try again."
+    return 1
+  fi
+
+  _kinghost_rest DELETE "dns" "name=$fulldomain&content=$txtvalue"
+  if ! echo "$response" | grep '"status":"ok"' >/dev/null; then
+    _err "Error"
+    _err "$response"
+    return 1
+  fi
+
+  return 0
+}
+
+####################  Private functions below ##################################
+_kinghost_rest() {
+  method=$1
+  uri="$2"
+  data="$3"
+  _debug "$uri"
+
+  export _H1="X-Auth-Email: $KINGHOST_Username"
+  export _H2="X-Auth-Key: $KINGHOST_Password"
+
+  if [ "$method" != "GET" ]; then
+    _debug data "$data"
+    response="$(_post "$data" "$KING_Api/$uri.json" "" "$method")"
+  else
+    response="$(_get "$KING_Api/$uri.json?$data")"
+  fi
+
+  if [ "$?" != "0" ]; then
+    _err "error $uri"
+    return 1
+  fi
+  _debug2 response "$response"
+  return 0
+}

+ 10 - 7
dnsapi/dns_pdns.sh

@@ -90,7 +90,7 @@ set_record() {
   full=$2
   full=$2
   txtvalue=$3
   txtvalue=$3
 
 
-  if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}"; then
+  if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [{\"name\": \"$full.\", \"type\": \"TXT\", \"content\": \"\\\"$txtvalue\\\"\", \"disabled\": false, \"ttl\": $PDNS_Ttl}]}]}"; then
     _err "Set txt record error."
     _err "Set txt record error."
     return 1
     return 1
   fi
   fi
@@ -107,7 +107,7 @@ rm_record() {
   root=$1
   root=$1
   full=$2
   full=$2
 
 
-  if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then
+  if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then
     _err "Delete txt record error."
     _err "Delete txt record error."
     return 1
     return 1
   fi
   fi
@@ -122,7 +122,7 @@ rm_record() {
 notify_slaves() {
 notify_slaves() {
   root=$1
   root=$1
 
 
-  if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root./notify"; then
+  if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root/notify"; then
     _err "Notify slaves error."
     _err "Notify slaves error."
     return 1
     return 1
   fi
   fi
@@ -144,15 +144,18 @@ _get_root() {
 
 
   while true; do
   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
 
 
     if _contains "$_zones_response" "\"name\": \"$h.\""; then
     if _contains "$_zones_response" "\"name\": \"$h.\""; then
-      _domain="$h"
+      _domain="$h."
+      if [ -z "$h" ]; then
+        _domain="=2E"
+      fi
       return 0
       return 0
     fi
     fi
 
 
+    if [ -z "$h" ]; then
+      return 1
+    fi
     i=$(_math $i + 1)
     i=$(_math $i + 1)
   done
   done
   _debug "$domain not found"
   _debug "$domain not found"

+ 3 - 3
dnsapi/dns_yandex.sh

@@ -50,9 +50,9 @@ _PDD_get_domain() {
   __last=0
   __last=0
   while [ $__last -eq 0 ]; do
   while [ $__last -eq 0 ]; do
     uri1="https://pddimp.yandex.ru/api2/admin/domain/domains?page=${__page}&on_page=20"
     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')
+    res1="$(_get "$uri1" | _normalizeJson)"
+    _debug2 "res1" "$res1"
+    __found="$(echo "$res1" | sed -n -e 's#.* "found": \([^,]*\),.*#\1#p')"
     _debug "found: $__found results on page"
     _debug "found: $__found results on page"
     if [ "$__found" -lt 20 ]; then
     if [ "$__found" -lt 20 ]; then
       _debug "last page: $__page"
       _debug "last page: $__page"