فهرست منبع

Merge branch 'acmesh-official:dev' into dev

Marvo2011 3 سال پیش
والد
کامیت
1584971908
5فایلهای تغییر یافته به همراه237 افزوده شده و 39 حذف شده
  1. 1 0
      .github/workflows/Linux.yml
  2. 49 38
      acme.sh
  3. 1 1
      dnsapi/dns_aws.sh
  4. 142 0
      dnsapi/dns_vercel.sh
  5. 44 0
      notify/callmebotWhatsApp.sh

+ 1 - 0
.github/workflows/Linux.yml

@@ -25,6 +25,7 @@ jobs:
     env:
       TEST_LOCAL: 1
       TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
+      TEST_ACME_Server: "LetsEncrypt.org_test"
     steps:
     - uses: actions/checkout@v2
     - name: Clone acmetest

+ 49 - 38
acme.sh

@@ -1,6 +1,6 @@
 #!/usr/bin/env sh
 
-VER=3.0.3
+VER=3.0.5
 
 PROJECT_NAME="acme.sh"
 
@@ -20,8 +20,6 @@ _SUB_FOLDER_DEPLOY="deploy"
 
 _SUB_FOLDERS="$_SUB_FOLDER_DNSAPI $_SUB_FOLDER_DEPLOY $_SUB_FOLDER_NOTIFY"
 
-CA_LETSENCRYPT_V1="https://acme-v01.api.letsencrypt.org/directory"
-
 CA_LETSENCRYPT_V2="https://acme-v02.api.letsencrypt.org/directory"
 CA_LETSENCRYPT_V2_TEST="https://acme-staging-v02.api.letsencrypt.org/directory"
 
@@ -2691,6 +2689,12 @@ _initAPI() {
   return 1
 }
 
+_clearCA() {
+  export CA_CONF=
+  export ACCOUNT_KEY_PATH=
+  export ACCOUNT_JSON_PATH=
+}
+
 #[domain]  [keylength or isEcc flag]
 _initpath() {
   domain="$1"
@@ -4382,10 +4386,6 @@ issue() {
     _alt_domains=""
   fi
 
-  if [ "$_key_length" = "$NO_VALUE" ]; then
-    _key_length=""
-  fi
-
   if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains" "$_pre_hook" "$_local_addr"; then
     _err "_on_before_issue."
     return 1
@@ -4406,7 +4406,13 @@ issue() {
   if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ]; then
     _info "Signing from existing CSR."
   else
+    # When renewing from an old version, the empty Le_Keylength means 2048.
+    # Note, do not use DEFAULT_DOMAIN_KEY_LENGTH as that value may change over
+    # time but an empty value implies 2048 specifically.
     _key=$(_readdomainconf Le_Keylength)
+    if [ -z "$_key" ]; then
+      _key=2048
+    fi
     _debug "Read key length:$_key"
     if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ] || [ "$Le_ForceNewDomainKey" = "1" ]; then
       if ! createDomainKey "$_main_domain" "$_key_length"; then
@@ -5241,18 +5247,20 @@ _split_cert_chain() {
   fi
 }
 
-#domain  [isEcc]
+#domain  [isEcc] [server]
 renew() {
   Le_Domain="$1"
   if [ -z "$Le_Domain" ]; then
-    _usage "Usage: $PROJECT_ENTRY --renew --domain <domain.tld> [--ecc]"
+    _usage "Usage: $PROJECT_ENTRY --renew --domain <domain.tld> [--ecc] [--server server]"
     return 1
   fi
 
   _isEcc="$2"
-  #the server specified from commandline
-  _acme_server_back="$ACME_DIRECTORY"
+  _renewServer="$3"
+  _debug "_renewServer" "$_renewServer"
+
   _initpath "$Le_Domain" "$_isEcc"
+
   _set_level=${NOTIFY_LEVEL:-$NOTIFY_LEVEL_DEFAULT}
   _info "$(__green "Renew: '$Le_Domain'")"
   if [ ! -f "$DOMAIN_CONF" ]; then
@@ -5266,17 +5274,6 @@ renew() {
 
   . "$DOMAIN_CONF"
   _debug Le_API "$Le_API"
-  if [ -z "$Le_API" ] || [ "$CA_LETSENCRYPT_V1" = "$Le_API" ]; then
-    #if this is from an old version, Le_API is empty,
-    #so, we force to use letsencrypt server
-    Le_API="$CA_LETSENCRYPT_V2"
-  fi
-
-  if [ "$_acme_server_back" ]; then
-    export ACME_DIRECTORY="$_acme_server_back"
-  else
-    export ACME_DIRECTORY="$Le_API"
-  fi
 
   case "$Le_API" in
   "$CA_LETSENCRYPT_V2_TEST")
@@ -5293,17 +5290,18 @@ renew() {
     ;;
   esac
 
-  if [ "$Le_API" ] && [ "$ACME_DIRECTORY" ]; then
-    if [ "$Le_API" != "$ACME_DIRECTORY" ]; then
-      _clearAPI
-    fi
-    #reload ca configs
-    ACCOUNT_KEY_PATH=""
-    ACCOUNT_JSON_PATH=""
-    CA_CONF=""
-    _debug2 "initpath again."
-    _initpath "$Le_Domain" "$_isEcc"
+  if [ "$_server" ]; then
+    Le_API="$_server"
   fi
+  _info "Renew to Le_API=$Le_API"
+
+  _clearAPI
+  _clearCA
+  export ACME_DIRECTORY="$Le_API"
+
+  #reload ca configs
+  _debug2 "initpath again."
+  _initpath "$Le_Domain" "$_isEcc"
 
   if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
     _info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")"
@@ -5327,6 +5325,13 @@ renew() {
   Le_PostHook="$(_readdomainconf Le_PostHook)"
   Le_RenewHook="$(_readdomainconf Le_RenewHook)"
   Le_Preferred_Chain="$(_readdomainconf Le_Preferred_Chain)"
+  # When renewing from an old version, the empty Le_Keylength means 2048.
+  # Note, do not use DEFAULT_DOMAIN_KEY_LENGTH as that value may change over
+  # time but an empty value implies 2048 specifically.
+  Le_Keylength="$(_readdomainconf Le_Keylength)"
+  if [ -z "$Le_Keylength" ]; then
+    Le_Keylength=2048
+  fi
   issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" "$Le_ChallengeAlias" "$Le_Preferred_Chain" "$Le_Valid_From" "$Le_Valid_To"
   res="$?"
   if [ "$res" != "0" ]; then
@@ -5354,11 +5359,16 @@ renew() {
   return "$res"
 }
 
-#renewAll  [stopRenewOnError]
+#renewAll  [stopRenewOnError] [server]
 renewAll() {
   _initpath
+  _clearCA
   _stopRenewOnError="$1"
   _debug "_stopRenewOnError" "$_stopRenewOnError"
+
+  _server="$2"
+  _debug "_server" "$_server"
+
   _ret="0"
   _success_msg=""
   _error_msg=""
@@ -5381,7 +5391,7 @@ renewAll() {
         _isEcc=$(echo "$d" | cut -d "$ECC_SEP" -f 2)
         d=$(echo "$d" | cut -d "$ECC_SEP" -f 1)
       fi
-      renew "$d" "$_isEcc"
+      renew "$d" "$_isEcc" "$_server"
     )
     rc="$?"
     _debug "Return code: $rc"
@@ -7087,8 +7097,8 @@ _process() {
   _altdomains="$NO_VALUE"
   _webroot=""
   _challenge_alias=""
-  _keylength=""
-  _accountkeylength=""
+  _keylength="$DEFAULT_DOMAIN_KEY_LENGTH"
+  _accountkeylength="$DEFAULT_ACCOUNT_KEY_LENGTH"
   _cert_file=""
   _key_file=""
   _ca_file=""
@@ -7654,6 +7664,7 @@ _process() {
 
   if [ "$_server" ]; then
     _selectServer "$_server" "${_ecc:-$_keylength}"
+    _server="$ACME_DIRECTORY"
   fi
 
   if [ "${_CMD}" != "install" ]; then
@@ -7728,10 +7739,10 @@ _process() {
     installcert "$_domain" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_ecc"
     ;;
   renew)
-    renew "$_domain" "$_ecc"
+    renew "$_domain" "$_ecc" "$_server"
     ;;
   renewAll)
-    renewAll "$_stopRenewOnError"
+    renewAll "$_stopRenewOnError" "$_server"
     ;;
   revoke)
     revoke "$_domain" "$_ecc" "$_revoke_reason"

+ 1 - 1
dnsapi/dns_aws.sh

@@ -152,7 +152,7 @@ dns_aws_rm() {
 
 _get_root() {
   domain=$1
-  i=2
+  i=1
   p=1
 
   if aws_rest GET "2013-04-01/hostedzone"; then

+ 142 - 0
dnsapi/dns_vercel.sh

@@ -0,0 +1,142 @@
+#!/usr/bin/env sh
+
+# Vercel DNS API
+#
+# This is your API token which can be acquired on the account page.
+# https://vercel.com/account/tokens
+#
+# VERCEL_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje"
+
+VERCEL_API="https://api.vercel.com"
+
+#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
+dns_vercel_add() {
+  fulldomain=$1
+  txtvalue=$2
+  _debug fulldomain "$fulldomain"
+  _debug txtvalue "$txtvalue"
+
+  VERCEL_TOKEN="${VERCEL_TOKEN:-$(_readaccountconf_mutable VERCEL_TOKEN)}"
+
+  if [ -z "$VERCEL_TOKEN" ]; then
+    VERCEL_TOKEN=""
+    _err "You have not set the Vercel API token yet."
+    _err "Please visit https://vercel.com/account/tokens to generate it."
+    return 1
+  fi
+
+  _saveaccountconf_mutable VERCEL_TOKEN "$VERCEL_TOKEN"
+
+  if ! _get_root "$fulldomain"; then
+    _err "invalid domain"
+    return 1
+  fi
+
+  _debug _sub_domain "$_sub_domain"
+  _debug _domain "$_domain"
+
+  _info "Adding record"
+  if _vercel_rest POST "v2/domains/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\"}"; then
+    if printf -- "%s" "$response" | grep "\"uid\":\"" >/dev/null; then
+      _info "Added"
+      return 0
+    else
+      _err "Unexpected response while adding text record."
+      return 1
+    fi
+  fi
+  _err "Add txt record error."
+}
+
+dns_vercel_rm() {
+  fulldomain=$1
+  txtvalue=$2
+
+  if ! _get_root "$fulldomain"; then
+    _err "invalid domain"
+    return 1
+  fi
+
+  _vercel_rest GET "v2/domains/$_domain/records"
+
+  count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$_sub_domain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ")
+
+  if [ "$count" = "0" ]; then
+    _info "Don't need to remove."
+  else
+    _record_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"slug\":\"[^,]*\",\"name\":\"$_sub_domain\",[^{]*\"type\":\"TXT\",\"value\":\"$txtvalue\"" | cut -d: -f2 | cut -d, -f1 | tr -d '"')
+
+    if [ "$_record_id" ]; then
+      echo "$_record_id" | while read -r item; do
+        if _vercel_rest DELETE "v2/domains/$_domain/records/$item"; then
+          _info "removed record" "$item"
+          return 0
+        else
+          _err "failed to remove record" "$item"
+          return 1
+        fi
+      done
+    fi
+  fi
+}
+
+####################  Private functions below ##################################
+#_acme-challenge.www.domain.com
+#returns
+# _sub_domain=_acme-challenge.www
+# _domain=domain.com
+_get_root() {
+  domain="$1"
+  ep="$2"
+  i=1
+  p=1
+  while true; do
+    h=$(printf "%s" "$domain" | cut -d . -f $i-100)
+    if [ -z "$h" ]; then
+      #not valid
+      return 1
+    fi
+
+    if ! _vercel_rest GET "v4/domains/$h"; then
+      return 1
+    fi
+
+    if _contains "$response" "\"name\":\"$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
+}
+
+_vercel_rest() {
+  m="$1"
+  ep="$2"
+  data="$3"
+
+  path="$VERCEL_API/$ep"
+
+  export _H1="Content-Type: application/json"
+  export _H2="Authorization: Bearer $VERCEL_TOKEN"
+
+  if [ "$m" != "GET" ]; then
+    _secure_debug2 data "$data"
+    response="$(_post "$data" "$path" "" "$m")"
+  else
+    response="$(_get "$path")"
+  fi
+  _ret="$?"
+  _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
+  _debug "http response code $_code"
+  _secure_debug2 response "$response"
+  if [ "$_ret" != "0" ]; then
+    _err "error $ep"
+    return 1
+  fi
+
+  response="$(printf "%s" "$response" | _normalizeJson)"
+  return 0
+}

+ 44 - 0
notify/callmebotWhatsApp.sh

@@ -0,0 +1,44 @@
+#!/usr/bin/env sh
+
+#Support CallMeBot Whatsapp webhooks
+
+#CALLMEBOT_YOUR_PHONE_NO=""
+#CALLMEBOT_API_KEY=""
+
+callmebotWhatsApp_send() {
+  _subject="$1"
+  _content="$2"
+  _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
+  _debug "_statusCode" "$_statusCode"
+
+  CALLMEBOT_YOUR_PHONE_NO="${CALLMEBOT_YOUR_PHONE_NO:-$(_readaccountconf_mutable CALLMEBOT_YOUR_PHONE_NO)}"
+  if [ -z "$CALLMEBOT_YOUR_PHONE_NO" ]; then
+    CALLMEBOT_YOUR_PHONE_NO=""
+    _err "You didn't specify a Slack webhook url CALLMEBOT_YOUR_PHONE_NO yet."
+    return 1
+  fi
+  _saveaccountconf_mutable CALLMEBOT_YOUR_PHONE_NO "$CALLMEBOT_YOUR_PHONE_NO"
+
+  CALLMEBOT_API_KEY="${CALLMEBOT_API_KEY:-$(_readaccountconf_mutable CALLMEBOT_API_KEY)}"
+  if [ "$CALLMEBOT_API_KEY" ]; then
+    _saveaccountconf_mutable CALLMEBOT_API_KEY "$CALLMEBOT_API_KEY"
+  fi
+
+  _waUrl="https://api.callmebot.com/whatsapp.php"
+
+  _Phone_No="$(printf "%s" "$CALLMEBOT_YOUR_PHONE_NO" | _url_encode)"
+  _apikey="$(printf "%s" "$CALLMEBOT_API_KEY" | _url_encode)"
+  _message="$(printf "*%s*\\n%s" "$_subject" "$_content" | _url_encode)"
+
+  _finalUrl="$_waUrl?phone=$_Phone_No&apikey=$_apikey&text=$_message"
+  response="$(_get "$_finalUrl")"
+
+  if [ "$?" = "0" ] && _contains ".<p><b>Message queued.</b> You will receive it in a few seconds."; then
+    _info "wa send success."
+    return 0
+  fi
+  _err "wa send error."
+  _debug "URL" "$_finalUrl"
+  _debug "Response" "$response"
+  return 1
+}