Browse Source

Merge pull request #2056 from Neilpang/dev

sync
neil 6 years ago
parent
commit
f62a4a0c0c
7 changed files with 319 additions and 5 deletions
  1. 1 0
      README.md
  2. 49 0
      deploy/README.md
  3. 92 0
      deploy/qiniu.sh
  4. 18 0
      dnsapi/README.md
  5. 141 0
      dnsapi/dns_active24.sh
  6. 1 1
      dnsapi/dns_dnsimple.sh
  7. 17 4
      dnsapi/dns_hostingde.sh

+ 1 - 0
README.md

@@ -349,6 +349,7 @@ You don't have to do anything manually!
 1. Neodigit.net API (https://www.neodigit.net)
 1. Exoscale.com API (https://www.exoscale.com/)
 1. PointDNS API (https://pointhq.com/)
+1. Active24.cz API (https://www.active24.cz/)
 
 And:
 

+ 49 - 0
deploy/README.md

@@ -332,3 +332,52 @@ variable to anything (ex: "1") before running `acme.sh`:
 ```sh
 export FABIO="1"
 ```
+
+## 13. Deploy your certificate to Qiniu.com
+
+使用 acme.sh 部署到七牛之前,需要确保部署的域名已打开 HTTPS 功能,您可以访问[融合 CDN - 域名管理](https://portal.qiniu.com/cdn/domain) 设置。
+另外还需要先导出 AK/SK 环境变量,您可以访问[密钥管理](https://portal.qiniu.com/user/key) 获得。
+
+```sh
+$ export QINIU_AK="foo"
+$ export QINIU_SK="bar"
+```
+
+完成准备工作之后,您就可以通过下面的命令开始部署 SSL 证书到七牛上:
+
+```sh
+$ acme.sh --deploy -d example.com --deploy-hook qiniu
+```
+
+假如您部署的证书为泛域名证书,您还需要设置 `QINIU_CDN_DOMAIN` 变量,指定实际需要部署的域名:
+
+```sh
+$ export QINIU_CDN_DOMAIN="cdn.example.com"
+$ acme.sh --deploy -d example.com --deploy-hook qiniu
+```
+
+### English version
+
+You should create AccessKey/SecretKey pair in https://portal.qiniu.com/user/key 
+before deploying your certificate, and please ensure you have enabled HTTPS for
+your domain name. You can enable it in https://portal.qiniu.com/cdn/domain.
+
+```sh
+$ export QINIU_AK="foo"
+$ export QINIU_SK="bar"
+```
+
+then you can deploy certificate by following command:
+
+```sh
+$ acme.sh --deploy -d example.com --deploy-hook qiniu
+```
+
+(Optional), If you are using wildcard certificate,
+you may need export `QINIU_CDN_DOMAIN` to specify which domain
+you want to update:
+
+```sh
+$ export QINIU_CDN_DOMAIN="cdn.example.com"
+$ acme.sh --deploy -d example.com --deploy-hook qiniu
+```

+ 92 - 0
deploy/qiniu.sh

@@ -0,0 +1,92 @@
+#!/usr/bin/env sh
+
+# Script to create certificate to qiniu.com 
+#
+# This deployment required following variables
+# export QINIU_AK="QINIUACCESSKEY"
+# export QINIU_SK="QINIUSECRETKEY"
+# export QINIU_CDN_DOMAIN="cdn.example.com"
+
+QINIU_API_BASE="https://api.qiniu.com"
+
+qiniu_deploy() {
+  _cdomain="$1"
+  _ckey="$2"
+  _ccert="$3"
+  _cca="$4"
+  _cfullchain="$5"
+
+  _debug _cdomain "$_cdomain"
+  _debug _ckey "$_ckey"
+  _debug _ccert "$_ccert"
+  _debug _cca "$_cca"
+  _debug _cfullchain "$_cfullchain"
+
+  if [ -z "$QINIU_AK" ]; then
+    _err "QINIU_AK is not defined."
+    return 1
+  else
+    _savedomainconf QINIU_AK "$QINIU_AK"
+  fi
+
+  if [ -z "$QINIU_SK" ]; then
+    _err "QINIU_SK is not defined."
+    return 1
+  else
+    _savedomainconf QINIU_SK "$QINIU_SK"
+  fi
+
+  if [ "$QINIU_CDN_DOMAIN" ]; then
+    _savedomainconf QINIU_CDN_DOMAIN "$QINIU_CDN_DOMAIN"
+  else
+    QINIU_CDN_DOMAIN="$_cdomain"
+  fi
+
+  ## upload certificate
+  string_fullchain=$(sed 's/$/\\n/' "$_cfullchain" | tr -d '\n')
+  string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n')
+
+  sslcert_path="/sslcert"
+  sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$QINIU_CDN_DOMAIN\",\"ca\":\"$string_fullchain\",\"pri\":\"$string_key\"}"
+  sslcert_access_token="$(_make_access_token "$sslcert_path")"
+  _debug sslcert_access_token "$sslcert_access_token"
+  export _H1="Authorization: QBox $sslcert_access_token"
+  sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64 "multiline")
+
+  if ! _contains "$sslcert_response" "certID"; then
+    _err "Error in creating certificate:"
+    _err "$sslcert_response"
+    return 1
+  fi
+
+  _debug sslcert_response "$sslcert_response"
+  _info "Certificate successfully uploaded, updating domain $_cdomain"
+
+  ## extract certId
+  _certId="$(printf "%s" "$sslcert_response" | _normalizeJson | _egrep_o "certID\": *\"[^\"]*\"" | cut -d : -f 2)"
+  _debug certId "$_certId"
+
+  ## update domain ssl config
+  update_path="/domain/$QINIU_CDN_DOMAIN/httpsconf"
+  update_body="{\"certid\":$_certId,\"forceHttps\":false}"
+  update_access_token="$(_make_access_token "$update_path")"
+  _debug update_access_token "$update_access_token"
+  export _H1="Authorization: QBox $update_access_token"
+  update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64 "multiline")
+
+  if _contains "$update_response" "error"; then
+    _err "Error in updating domain httpsconf:"
+    _err "$update_response"
+    return 1
+  fi
+
+  _debug update_response "$update_response"
+  _info "Certificate successfully deployed"
+
+  return 0
+}
+
+_make_access_token() {
+  _token="$(printf "%s\n" "$1" | _hmac "sha1" "$(printf "%s" "$QINIU_SK" | _hex_dump | tr -d " ")" | _base64)"
+  echo "$QINIU_AK:$_token"
+}

+ 18 - 0
dnsapi/README.md

@@ -1139,6 +1139,24 @@ You can then issue certs by using:
 ```acme.sh --issue --dns dns_pointhq -d example.com -d www.example.com
 ```
 
+## 59. Use Active24 API
+
+Create an API token in the Active24 account section, documentation on https://faq.active24.com/cz/790131-REST-API-rozhran%C3%AD.
+
+Set your API token:
+
+```
+export ACTIVE24_Token='xxx'
+```
+
+Now, let's issue a cert, set `dnssleep` for propagation new DNS record:
+```
+acme.sh --issue --dns dns_active24 -d example.com -d www.example.com --dnssleep 1000
+```
+
+The `ACTIVE24_Token` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
+
+
 # Use custom API
 
 If your API is not supported yet, you can write your own DNS API.

+ 141 - 0
dnsapi/dns_active24.sh

@@ -0,0 +1,141 @@
+#!/usr/bin/env sh
+
+#ACTIVE24_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
+
+ACTIVE24_Api="https://api.active24.com"
+
+########  Public functions #####################
+
+# Usage: add  _acme-challenge.www.domain.com   "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
+# Used to add txt record
+dns_active24_add() {
+  fulldomain=$1
+  txtvalue=$2
+
+  _active24_init
+
+  _info "Adding txt record"
+  if _active24_rest POST "dns/$_domain/txt/v1" "{\"name\":\"$_sub_domain\",\"text\":\"$txtvalue\",\"ttl\":0}"; then
+    if _contains "$response" "errors"; then
+      _err "Add txt record error."
+      return 1
+    else
+      _info "Added, OK"
+      return 0
+    fi
+  fi
+  _err "Add txt record error."
+  return 1
+}
+
+# Usage: fulldomain txtvalue
+# Used to remove the txt record after validation
+dns_active24_rm() {
+  fulldomain=$1
+  txtvalue=$2
+
+  _active24_init
+
+  _debug "Getting txt records"
+  _active24_rest GET "dns/$_domain/records/v1"
+
+  if _contains "$response" "errors"; then
+    _err "Error"
+    return 1
+  fi
+
+  hash_ids=$(echo "$response" | _egrep_o "[^{]+${txtvalue}[^}]+" | _egrep_o "hashId\":\"[^\"]+" | cut -c10-)
+
+  for hash_id in $hash_ids; do
+    _debug "Removing hash_id" "$hash_id"
+    if _active24_rest DELETE "dns/$_domain/$hash_id/v1" ""; then
+      if _contains "$response" "errors"; then
+        _err "Unable to remove txt record."
+        return 1
+      else
+        _info "Removed txt record."
+        return 0
+      fi
+    fi
+  done
+
+  _err "No txt records found."
+  return 1
+}
+
+####################  Private functions below ##################################
+#_acme-challenge.www.domain.com
+#returns
+# _sub_domain=_acme-challenge.www
+# _domain=domain.com
+# _domain_id=sdjkglgdfewsdfg
+_get_root() {
+  domain=$1
+
+  if ! _active24_rest GET "dns/domains/v1"; then
+    return 1
+  fi
+
+  i=2
+  p=1
+  while true; do
+    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
+    _debug "h" "$h"
+    if [ -z "$h" ]; then
+      #not valid
+      return 1
+    fi
+
+    if _contains "$response" "\"$h\"" >/dev/null; then
+      _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
+      _domain=$h
+      return 0
+    fi
+    p=$i
+    i=$(_math "$i" + 1)
+  done
+  return 1
+}
+
+_active24_rest() {
+  m=$1
+  ep="$2"
+  data="$3"
+  _debug "$ep"
+
+  export _H1="Authorization: Bearer $ACTIVE24_Token"
+
+  if [ "$m" != "GET" ]; then
+    _debug "data" "$data"
+    response="$(_post "$data" "$ACTIVE24_Api/$ep" "" "$m" "application/json")"
+  else
+    response="$(_get "$ACTIVE24_Api/$ep")"
+  fi
+
+  if [ "$?" != "0" ]; then
+    _err "error $ep"
+    return 1
+  fi
+  _debug2 response "$response"
+  return 0
+}
+
+_active24_init() {
+  ACTIVE24_Token="${ACTIVE24_Token:-$(_readaccountconf_mutable ACTIVE24_Token)}"
+  if [ -z "$ACTIVE24_Token" ]; then
+    ACTIVE24_Token=""
+    _err "You didn't specify a Active24 api token yet."
+    _err "Please create the token and try again."
+    return 1
+  fi
+
+  _saveaccountconf_mutable ACTIVE24_Token "ACTIVE24_Token"
+
+  _debug "First detect the root zone"
+  if ! _get_root "$fulldomain"; then
+    _err "invalid domain"
+    return 1
+  fi
+  _debug _sub_domain "$_sub_domain"
+  _debug _domain "$_domain"
+}

+ 1 - 1
dnsapi/dns_dnsimple.sh

@@ -152,7 +152,7 @@ _get_records() {
   sub_domain=$3
 
   _debug "fetching txt records"
-  _dnsimple_rest GET "$account_id/zones/$domain/records?per_page=100"
+  _dnsimple_rest GET "$account_id/zones/$domain/records?per_page=5000&sort=id:desc"
 
   if ! _contains "$response" "\"id\":"; then
     _err "failed to retrieve records"

+ 17 - 4
dnsapi/dns_hostingde.sh

@@ -59,9 +59,22 @@ _hostingde_getZoneConfig() {
     if _contains "${curResult}" '"totalEntries": 1'; then
       _info "Retrieved zone data."
       _debug "Zone data: '${curResult}'"
-
-      # read ZoneConfigId for later update
       zoneConfigId=$(echo "${curResult}" | _egrep_o '"id":.*' | cut -d ':' -f 2 | cut -d '"' -f 2)
+      zoneConfigName=$(echo "${curResult}" | _egrep_o '"name":.*' | cut -d ':' -f 2 | cut -d '"' -f 2)
+      zoneConfigType=$(echo "${curResult}" | grep -v "FindZoneConfigsResult" | _egrep_o '"type":.*' | cut -d ':' -f 2 | cut -d '"' -f 2)
+      zoneConfigExpire=$(echo "${curResult}" | _egrep_o '"expire":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1)
+      zoneConfigNegativeTtl=$(echo "${curResult}" | _egrep_o '"negativeTtl":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1)
+      zoneConfigRefresh=$(echo "${curResult}" | _egrep_o '"refresh":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1)
+      zoneConfigRetry=$(echo "${curResult}" | _egrep_o '"retry":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1)
+      zoneConfigTtl=$(echo "${curResult}" | _egrep_o '"ttl":.*' | cut -d ':' -f 2 | cut -d '"' -f 2 | cut -d ',' -f 1)
+      zoneConfigDnsServerGroupId=$(echo "${curResult}" | _egrep_o '"dnsServerGroupId":.*' | cut -d ':' -f 2 | cut -d '"' -f 2)
+      zoneConfigEmailAddress=$(echo "${curResult}" | _egrep_o '"emailAddress":.*' | cut -d ':' -f 2 | cut -d '"' -f 2)
+      zoneConfigDnsSecMode=$(echo "${curResult}" | _egrep_o '"dnsSecMode":.*' | cut -d ':' -f 2 | cut -d '"' -f 2)
+      if [ "${zoneConfigType}" != "NATIVE" ]; then
+        _err "Zone is not native"
+        returnCode=1
+        break
+      fi
       _debug "zoneConfigId '${zoneConfigId}'"
       returnCode=0
       break
@@ -94,7 +107,7 @@ _hostingde_addRecord() {
     _hostingde_getZoneStatus
     _debug "Result of zoneStatus: '${zoneStatus}'"
   done
-  curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\"},\"recordsToAdd\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\",\"ttl\":3600}]}"
+  curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\",\"name\":\"${zoneConfigName}\",\"type\":\"${zoneConfigType}\",\"dnsServerGroupId\":\"${zoneConfigDnsServerGroupId}\",\"dnsSecMode\":\"${zoneConfigDnsSecMode}\",\"emailAddress\":\"${zoneConfigEmailAddress}\",\"soaValues\":{\"expire\":${zoneConfigExpire},\"negativeTtl\":${zoneConfigNegativeTtl},\"refresh\":${zoneConfigRefresh},\"retry\":${zoneConfigRetry},\"ttl\":${zoneConfigTtl}}},\"recordsToAdd\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\",\"ttl\":3600}]}"
   curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")"
   _debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'"
   _debug "Result of zoneUpdate: '$curResult'"
@@ -118,7 +131,7 @@ _hostingde_removeRecord() {
     _hostingde_getZoneStatus
     _debug "Result of zoneStatus: '$zoneStatus'"
   done
-  curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\"},\"recordsToDelete\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\"}]}"
+  curData="{\"authToken\":\"${HOSTINGDE_APIKEY}\",\"zoneConfig\":{\"id\":\"${zoneConfigId}\",\"name\":\"${zoneConfigName}\",\"type\":\"${zoneConfigType}\",\"dnsServerGroupId\":\"${zoneConfigDnsServerGroupId}\",\"dnsSecMode\":\"${zoneConfigDnsSecMode}\",\"emailAddress\":\"${zoneConfigEmailAddress}\",\"soaValues\":{\"expire\":${zoneConfigExpire},\"negativeTtl\":${zoneConfigNegativeTtl},\"refresh\":${zoneConfigRefresh},\"retry\":${zoneConfigRetry},\"ttl\":${zoneConfigTtl}}},\"recordsToDelete\":[{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"\\\"${txtvalue}\\\"\"}]}"
   curResult="$(_post "${curData}" "${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate")"
   _debug "Calling zoneUpdate: '${curData}' '${HOSTINGDE_ENDPOINT}/api/dns/v1/json/zoneUpdate'"
   _debug "Result of zoneUpdate: '$curResult'"