Browse Source

Merge branch 'master' into patch-2

shar0119 8 years ago
parent
commit
8e15c48092
9 changed files with 251 additions and 27 deletions
  1. 8 1
      Dockerfile
  2. 1 0
      README.md
  3. 43 20
      acme.sh
  4. 15 0
      dnsapi/README.md
  5. 16 0
      dnsapi/dns_aws.sh
  6. 15 2
      dnsapi/dns_cf.sh
  7. 3 3
      dnsapi/dns_freedns.sh
  8. 1 1
      dnsapi/dns_ovh.sh
  9. 149 0
      dnsapi/dns_vscale.sh

+ 8 - 1
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"]

+ 1 - 0
README.md

@@ -317,6 +317,7 @@ You don't have to do anything manually!
 1. VSCALE (https://vscale.io/)
 1. Dynu API (https://www.dynu.com)
 
+
 **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.

+ 43 - 20
acme.sh

@@ -1,6 +1,6 @@
 #!/usr/bin/env sh
 
-VER=2.6.8
+VER=2.6.9
 
 PROJECT_NAME="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
@@ -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
@@ -1102,12 +1102,13 @@ _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 ' '
+    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
 }
 
@@ -1191,7 +1192,7 @@ toPkcs8() {
 
 }
 
-#[2048]  
+#[2048]
 createAccountKey() {
   _info "Creating account key"
   if [ -z "$1" ]; then
@@ -1846,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"
@@ -2527,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"
 
@@ -2564,7 +2583,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
@@ -3114,12 +3133,16 @@ __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/ "
     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"
@@ -3643,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
@@ -3860,7 +3883,7 @@ renewAll() {
         return "$rc"
       else
         _ret="$rc"
-        _err "Error renew $d, Go ahead to next one."
+        _err "Error renew $d."
       fi
     fi
   done
@@ -4784,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.
@@ -4798,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.

+ 15 - 0
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.
 
+
+## 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
+```
+
+
 # Use custom API
 
 If your API is not supported yet, you can write your own DNS API.

+ 16 - 0
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
@@ -208,6 +221,9 @@ aws_rest() {
   _debug _H2 "$_H2"
 
   url="$AWS_URL/$ep"
+  if [ "$qsr" ]; then
+    url="$AWS_URL/$ep?$qsr"
+  fi
 
   if [ "$mtd" = "GET" ]; then
     response="$(_get "$url")"

+ 15 - 2
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
@@ -83,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"

+ 3 - 3
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

+ 1 - 1
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'

+ 149 - 0
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
+}