]> git.proxmox.com Git - mirror_acme.sh.git/commitdiff
Merge pull request #2243 from mod242/master
authorneil <github@byneil.com>
Fri, 3 May 2019 12:35:34 +0000 (20:35 +0800)
committerGitHub <noreply@github.com>
Fri, 3 May 2019 12:35:34 +0000 (20:35 +0800)
New API for Schlundtech.de

acme.sh
deploy/gcore_cdn.sh
deploy/haproxy.sh
dnsapi/dns_ddnss.sh
notify/mail.sh [new file with mode: 0644]
notify/mailgun.sh [new file with mode: 0644]
notify/pop.sh [new file with mode: 0644]
notify/sendgrid.sh [new file with mode: 0644]
notify/smtp.sh [new file with mode: 0644]

diff --git a/acme.sh b/acme.sh
index 0ce42ff5e84edad0cfe0306c82991b0398d34033..dc110a0f1beb96136404787f7e3088e6a4f78ca3 100755 (executable)
--- a/acme.sh
+++ b/acme.sh
@@ -1,6 +1,6 @@
 #!/usr/bin/env sh
 
-VER=2.8.1
+VER=2.8.2
 
 PROJECT_NAME="acme.sh"
 
@@ -14,7 +14,11 @@ _WINDOWS_SCHEDULER_NAME="$PROJECT_NAME.cron"
 
 _SCRIPT_="$0"
 
-_SUB_FOLDERS="dnsapi deploy"
+_SUB_FOLDER_NOTIFY="notify"
+_SUB_FOLDER_DNSAPI="dnsapi"
+_SUB_FOLDER_DEPLOY="deploy"
+
+_SUB_FOLDERS="$_SUB_FOLDER_DNSAPI $_SUB_FOLDER_DEPLOY $_SUB_FOLDER_NOTIFY"
 
 LETSENCRYPT_CA_V1="https://acme-v01.api.letsencrypt.org/directory"
 LETSENCRYPT_STAGING_CA_V1="https://acme-staging.api.letsencrypt.org/directory"
@@ -107,6 +111,18 @@ SYSLOG_LEVEL_DEFAULT=$SYSLOG_LEVEL_ERROR
 #none
 SYSLOG_LEVEL_NONE=0
 
+NOTIFY_LEVEL_DISABLE=0
+NOTIFY_LEVEL_ERROR=1
+NOTIFY_LEVEL_RENEW=2
+NOTIFY_LEVEL_SKIP=3
+
+NOTIFY_LEVEL_DEFAULT=$NOTIFY_LEVEL_RENEW
+
+NOTIFY_MODE_BULK=0
+NOTIFY_MODE_CERT=1
+
+NOTIFY_MODE_DEFAULT=$NOTIFY_MODE_BULK
+
 _DEBUG_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh"
 
 _PREPARE_LINK="https://github.com/Neilpang/acme.sh/wiki/Install-preparations"
@@ -117,6 +133,8 @@ _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"
 
+_NOTIFY_WIKI="https://github.com/Neilpang/acme.sh/wiki/notify"
+
 _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"
@@ -784,6 +802,13 @@ _url_encode() {
   done
 }
 
+_json_encode() {
+  _j_str="$(sed 's/"/\\"/g' | sed "s/\r/\\r/g")"
+  _debug3 "_json_encode"
+  _debug3 "_j_str" "$_j_str"
+  echo "$_j_str" | _hex_dump | _lower_case | sed 's/0a/5c 6e/g' | tr -d ' ' | _h2b | tr -d "\r\n"
+}
+
 #options file
 _sed_i() {
   options="$1"
@@ -3168,6 +3193,14 @@ _on_issue_err() {
     _err "See: $_DEBUG_WIKI"
   fi
 
+  if [ "$IN_CRON" ]; then
+    if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_ERROR ]; then
+      if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then
+        _send_notify "Renew $_main_domain error" "There is an error." "$NOTIFY_HOOK" 1
+      fi
+    fi
+  fi
+
   #run the post hook
   if [ "$_chk_post_hook" ]; then
     _info "Run post hook:'$_chk_post_hook'"
@@ -3210,6 +3243,13 @@ _on_issue_success() {
   _chk_post_hook="$1"
   _chk_renew_hook="$2"
   _debug _on_issue_success
+  if [ "$IN_CRON" ]; then
+    if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_RENEW ]; then
+      if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then
+        _send_notify "Renew $_main_domain success" "Good, the cert is renewed." "$NOTIFY_HOOK" 0
+      fi
+    fi
+  fi
   #run the post hook
   if [ "$_chk_post_hook" ]; then
     _info "Run post hook:'$_chk_post_hook'"
@@ -3467,9 +3507,9 @@ _findHook() {
     d_api="$_SCRIPT_HOME/$_hookcat/$_hookname"
   elif [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname.sh" ]; then
     d_api="$_SCRIPT_HOME/$_hookcat/$_hookname.sh"
-  elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ]; then
+  elif [ "$_hookdomain" ] && [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ]; then
     d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname"
-  elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" ]; then
+  elif [ "$_hookdomain" ] && [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" ]; then
     d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname.sh"
   elif [ -f "$LE_WORKING_DIR/$_hookname" ]; then
     d_api="$LE_WORKING_DIR/$_hookname"
@@ -4017,7 +4057,7 @@ $_authorizations_map"
         txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)"
         _debug txt "$txt"
 
-        d_api="$(_findHook "$_dns_root_d" dnsapi "$_currentRoot")"
+        d_api="$(_findHook "$_dns_root_d" $_SUB_FOLDER_DNSAPI "$_currentRoot")"
         _debug d_api "$d_api"
 
         dns_entry="$dns_entry$dvsep$txt${dvsep}$d_api"
@@ -4622,6 +4662,15 @@ renew() {
   if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
     _info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")"
     _info "Add '$(__red '--force')' to force to renew."
+
+    if [ "$IN_CRON" = "1" ]; then
+      if [ "$NOTIFY_LEVEL" ] && [ $NOTIFY_LEVEL -ge $NOTIFY_LEVEL_SKIP ]; then
+        if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then
+          _send_notify "Renew $Le_Domain skipped" "Good, the cert next renewal time is $Le_NextRenewTimeStr." "$NOTIFY_HOOK" "$RENEW_SKIP"
+        fi
+      fi
+    fi
+
     return "$RENEW_SKIP"
   fi
 
@@ -4657,7 +4706,9 @@ renewAll() {
   _stopRenewOnError="$1"
   _debug "_stopRenewOnError" "$_stopRenewOnError"
   _ret="0"
-
+  _success_msg=""
+  _error_msg=""
+  _skipped_msg=""
   for di in "${CERT_HOME}"/*.*/; do
     _debug di "$di"
     if ! [ -d "$di" ]; then
@@ -4678,15 +4729,49 @@ renewAll() {
     if [ "$rc" != "0" ]; then
       if [ "$rc" = "$RENEW_SKIP" ]; then
         _info "Skipped $d"
-      elif [ "$_stopRenewOnError" ]; then
-        _err "Error renew $d,  stop now."
-        return "$rc"
+        _skipped_msg="${_skipped_msg}    $d
+"
       else
-        _ret="$rc"
-        _err "Error renew $d."
+        _error_msg="${_error_msg}    $d
+"
+        if [ "$_stopRenewOnError" ]; then
+          _err "Error renew $d,  stop now."
+          _ret="$rc"
+          break
+        else
+          _ret="$rc"
+          _err "Error renew $d."
+        fi
       fi
+    else
+      _success_msg="${_success_msg}    $d
+"
     fi
   done
+
+  if [ "$IN_CRON" = "1" ]; then
+    if [ -z "$NOTIFY_MODE" ] || [ "$NOTIFY_MODE" = "$NOTIFY_MODE_BULK" ]; then
+      _msg_subject="Renew"
+      if [ "$_error_msg" ]; then
+        _msg_subject="${_msg_subject} Error"
+      fi
+      if [ "$_success_msg" ]; then
+        _msg_subject="${_msg_subject} Success"
+      fi
+      if [ "$_skipped_msg" ]; then
+        _msg_subject="${_msg_subject} Skipped"
+      fi
+      _msg_data="Error certs:
+${_error_msg}
+Success certs:
+${_success_msg}
+Skipped certs:
+$_skipped_msg
+"
+      _send_notify "$_msg_subject" "$_msg_data" "$NOTIFY_HOOK" 0
+    fi
+  fi
+
   return "$_ret"
 }
 
@@ -4835,7 +4920,7 @@ _deploy() {
   _hooks="$2"
 
   for _d_api in $(echo "$_hooks" | tr ',' " "); do
-    _deployApi="$(_findHook "$_d" deploy "$_d_api")"
+    _deployApi="$(_findHook "$_d" $_SUB_FOLDER_DEPLOY "$_d_api")"
     if [ -z "$_deployApi" ]; then
       _err "The deploy hook $_d_api is not found."
       return 1
@@ -5785,6 +5870,113 @@ version() {
   echo "v$VER"
 }
 
+# subject content hooks code
+_send_notify() {
+  _nsubject="$1"
+  _ncontent="$2"
+  _nhooks="$3"
+  _nerror="$4"
+
+  if [ "$NOTIFY_LEVEL" = "$NOTIFY_LEVEL_DISABLE" ]; then
+    _debug "The NOTIFY_LEVEL is $NOTIFY_LEVEL, disabled, just return."
+    return 0
+  fi
+
+  if [ -z "$_nhooks" ]; then
+    _debug "The NOTIFY_HOOK is empty, just return."
+    return 0
+  fi
+
+  _send_err=0
+  for _n_hook in $(echo "$_nhooks" | tr ',' " "); do
+    _n_hook_file="$(_findHook "" $_SUB_FOLDER_NOTIFY "$_n_hook")"
+    _info "Found $_n_hook_file"
+
+    if ! (
+      if ! . "$_n_hook_file"; then
+        _err "Load file $_n_hook_file error. Please check your api file and try again."
+        return 1
+      fi
+
+      d_command="${_n_hook}_send"
+      if ! _exists "$d_command"; then
+        _err "It seems that your api file is not correct, it must have a function named: $d_command"
+        return 1
+      fi
+
+      if ! $d_command "$_nsubject" "$_ncontent" "$_nerror"; then
+        _err "Error send message by $d_command"
+        return 1
+      fi
+
+      return 0
+    ); then
+      _err "Set $_n_hook_file error."
+      _send_err=1
+    else
+      _info "$_n_hook $(__green Success)"
+    fi
+  done
+  return $_send_err
+
+}
+
+# hook
+_set_notify_hook() {
+  _nhooks="$1"
+
+  _test_subject="Hello, this is notification from $PROJECT_NAME"
+  _test_content="If you receive this email, your notification works."
+
+  _send_notify "$_test_subject" "$_test_content" "$_nhooks" 0
+
+}
+
+#[hook] [level] [mode]
+setnotify() {
+  _nhook="$1"
+  _nlevel="$2"
+  _nmode="$3"
+
+  _initpath
+
+  if [ -z "$_nhook$_nlevel$_nmode" ]; then
+    _usage "Usage: $PROJECT_ENTRY --set-notify [--notify-hook mailgun] [--notify-level $NOTIFY_LEVEL_DEFAULT] [--notify-mode $NOTIFY_MODE_DEFAULT]"
+    _usage "$_NOTIFY_WIKI"
+    return 1
+  fi
+
+  if [ "$_nlevel" ]; then
+    _info "Set notify level to: $_nlevel"
+    export "NOTIFY_LEVEL=$_nlevel"
+    _saveaccountconf "NOTIFY_LEVEL" "$NOTIFY_LEVEL"
+  fi
+
+  if [ "$_nmode" ]; then
+    _info "Set notify mode to: $_nmode"
+    export "NOTIFY_MODE=$_nmode"
+    _saveaccountconf "NOTIFY_MODE" "$NOTIFY_MODE"
+  fi
+
+  if [ "$_nhook" ]; then
+    _info "Set notify hook to: $_nhook"
+    if [ "$_nhook" = "$NO_VALUE" ]; then
+      _info "Clear notify hook"
+      _clearaccountconf "NOTIFY_HOOK"
+    else
+      if _set_notify_hook "$_nhook"; then
+        export NOTIFY_HOOK="$_nhook"
+        _saveaccountconf "NOTIFY_HOOK" "$NOTIFY_HOOK"
+        return 0
+      else
+        _err "Can not set notify hook to: $_nhook"
+        return 1
+      fi
+    fi
+  fi
+
+}
+
 showhelp() {
   _initpath
   version
@@ -5817,6 +6009,8 @@ Commands:
   --create-domain-key      Create an domain private key, professional use.
   --createCSR, -ccsr       Create CSR , professional use.
   --deactivate             Deactivate the domain authz, professional use.
+  --set-notify             Set the cron notification hook, level or mode.
+
 
 Parameters:
   --domain, -d   domain.tld         Specifies a domain, used to issue, renew or revoke etc.
@@ -5885,7 +6079,18 @@ Parameters:
   --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
   --branch, -b                      Only valid for '--upgrade' command, specifies the branch name to upgrade to.
-  "
+
+  --notify-level  0|1|2|3           Set the notification level:  Default value is $NOTIFY_LEVEL_DEFAULT.
+                                     0: disabled, no notification will be sent. 
+                                     1: send notification only when there is an error. No news is good news.
+                                     2: send notification when a cert is successfully renewed, or there is an error
+                                     3: send notification when a cert is skipped, renewdd, or error
+  --notify-mode   0|1               Set notification mode. Default value is $NOTIFY_MODE_DEFAULT.
+                                     0: Bulk mode. Send all the domain's notifications in one message(mail)
+                                     1: Cert mode. Send a message for every single cert.
+  --notify-hook   [hookname]        Set the notify hook
+
+"
 }
 
 # nocron noprofile
@@ -6019,6 +6224,9 @@ _process() {
   _syslog=""
   _use_wget=""
   _server=""
+  _notify_hook=""
+  _notify_level=""
+  _notify_mode=""
   while [ ${#} -gt 0 ]; do
     case "${1}" in
 
@@ -6105,6 +6313,9 @@ _process() {
       --deactivate-account)
         _CMD="deactivateaccount"
         ;;
+      --set-notify)
+        _CMD="setnotify"
+        ;;
       --domain | -d)
         _dvalue="$2"
 
@@ -6453,6 +6664,37 @@ _process() {
         export BRANCH="$2"
         shift
         ;;
+      --notify-hook)
+        _nhook="$2"
+        if _startswith "$_nhook" "-"; then
+          _err "'$_nhook' is not a hook name for '$1'"
+          return 1
+        fi
+        if [ "$_notify_hook" ]; then
+          _notify_hook="$_notify_hook,$_nhook"
+        else
+          _notify_hook="$_nhook"
+        fi
+        shift
+        ;;
+      --notify-level)
+        _nlevel="$2"
+        if _startswith "$_nlevel" "-"; then
+          _err "'$_nlevel' is not a integer for '$1'"
+          return 1
+        fi
+        _notify_level="$_nlevel"
+        shift
+        ;;
+      --notify-mode)
+        _nmode="$2"
+        if _startswith "$_nmode" "-"; then
+          _err "'$_nmode' is not a integer for '$1'"
+          return 1
+        fi
+        _notify_mode="$_nmode"
+        shift
+        ;;
       *)
         _err "Unknown parameter : $1"
         return 1
@@ -6570,7 +6812,9 @@ _process() {
     createCSR)
       createCSR "$_domain" "$_altdomains" "$_ecc"
       ;;
-
+    setnotify)
+      setnotify "$_notify_hook" "$_notify_level" "$_notify_mode"
+      ;;
     *)
       if [ "$_CMD" ]; then
         _err "Invalid command: $_CMD"
index 56ca9afdc5995ab18d10ddb9dcd847d3527e7a9c..e0921bcbdba14d491fdeac3e96d74697795f52a2 100644 (file)
@@ -27,8 +27,8 @@ gcore_cdn_deploy() {
   _debug _cca "$_cca"
   _debug _cfullchain "$_cfullchain"
 
-  _fullchain=$(tr '\n\r' '@#' <"$_cfullchain" | sed 's/@/\\n/g;s/#/\\r/g')
-  _key=$(tr '\n\r' '@#' <"$_ckey" | sed 's/@/\\n/g;s/#/\\r/g')
+  _fullchain=$(tr '\r\n' '*#' <"$_cfullchain" | sed 's/*#/#/g;s/##/#/g;s/#/\\n/g')
+  _key=$(tr '\r\n' '*#' <"$_ckey" | sed 's/*#/#/g;s/#/\\n/g')
 
   _debug _fullchain "$_fullchain"
   _debug _key "$_key"
index 5c1a40e25e5db5946c3118bcfa24c0077d46687e..2479aebdc12e5227389f5b5daff6a404e3229f78 100644 (file)
@@ -1,8 +1,41 @@
 #!/usr/bin/env sh
 
-#Here is a script to deploy cert to haproxy server.
-
-#returns 0 means success, otherwise error.
+# Script for acme.sh to deploy certificates to haproxy
+#
+# The following variables can be exported:
+#
+# export DEPLOY_HAPROXY_PEM_NAME="${domain}.pem"
+#
+# Defines the name of the PEM file.
+# Defaults to "<domain>.pem"
+#
+# export DEPLOY_HAPROXY_PEM_PATH="/etc/haproxy"
+#
+# Defines location of PEM file for HAProxy.
+# Defaults to /etc/haproxy
+#
+# export DEPLOY_HAPROXY_RELOAD="systemctl reload haproxy"
+#
+# OPTIONAL: Reload command used post deploy
+# This defaults to be a no-op (ie "true").
+# It is strongly recommended to set this something that makes sense
+# for your distro.
+#
+# export DEPLOY_HAPROXY_ISSUER="no"
+#
+# OPTIONAL: Places CA file as "${DEPLOY_HAPROXY_PEM}.issuer"
+# Note: Required for OCSP stapling to work
+#
+# export DEPLOY_HAPROXY_BUNDLE="no"
+#
+# OPTIONAL: Deploy this certificate as part of a multi-cert bundle
+# This adds a suffix to the certificate based on the certificate type
+# eg RSA certificates will have .rsa as a suffix to the file name
+# HAProxy will load all certificates and provide one or the other
+# depending on client capabilities
+# Note: This functionality requires HAProxy was compiled against
+# a version of OpenSSL that supports this.
+#
 
 ########  Public functions #####################
 
@@ -14,45 +47,226 @@ haproxy_deploy() {
   _cca="$4"
   _cfullchain="$5"
 
-  _debug _cdomain "$_cdomain"
-  _debug _ckey "$_ckey"
-  _debug _ccert "$_ccert"
-  _debug _cca "$_cca"
-  _debug _cfullchain "$_cfullchain"
-
-  # handle reload preference
-  DEFAULT_HAPROXY_RELOAD="/usr/sbin/service haproxy restart"
-  if [ -z "${DEPLOY_HAPROXY_RELOAD}" ]; then
-    _reload="${DEFAULT_HAPROXY_RELOAD}"
-    _cleardomainconf DEPLOY_HAPROXY_RELOAD
-  else
-    _reload="${DEPLOY_HAPROXY_RELOAD}"
-    _savedomainconf DEPLOY_HAPROXY_RELOAD "$DEPLOY_HAPROXY_RELOAD"
+  # Some defaults
+  DEPLOY_HAPROXY_PEM_PATH_DEFAULT="/etc/haproxy"
+  DEPLOY_HAPROXY_PEM_NAME_DEFAULT="${_cdomain}.pem"
+  DEPLOY_HAPROXY_BUNDLE_DEFAULT="no"
+  DEPLOY_HAPROXY_ISSUER_DEFAULT="no"
+  DEPLOY_HAPROXY_RELOAD_DEFAULT="true"
+
+  if [ -f "${DOMAIN_CONF}" ]; then
+    # shellcheck disable=SC1090
+    . "${DOMAIN_CONF}"
+  fi
+
+  _debug _cdomain "${_cdomain}"
+  _debug _ckey "${_ckey}"
+  _debug _ccert "${_ccert}"
+  _debug _cca "${_cca}"
+  _debug _cfullchain "${_cfullchain}"
+
+  # PEM_PATH is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_PATH_DEFAULT}"
+  if [ -n "${DEPLOY_HAPROXY_PEM_PATH}" ]; then
+    Le_Deploy_haproxy_pem_path="${DEPLOY_HAPROXY_PEM_PATH}"
+    _savedomainconf Le_Deploy_haproxy_pem_path "${Le_Deploy_haproxy_pem_path}"
+  elif [ -z "${Le_Deploy_haproxy_pem_path}" ]; then
+    Le_Deploy_haproxy_pem_path="${DEPLOY_HAPROXY_PEM_PATH_DEFAULT}"
   fi
-  _savedomainconf DEPLOY_HAPROXY_PEM_PATH "$DEPLOY_HAPROXY_PEM_PATH"
 
-  # work out the path where the PEM file should go
-  _pem_path="${DEPLOY_HAPROXY_PEM_PATH}"
-  if [ -z "$_pem_path" ]; then
-    _err "Path to save PEM file not found. Please define DEPLOY_HAPROXY_PEM_PATH."
+  # Ensure PEM_PATH exists
+  if [ -d "${Le_Deploy_haproxy_pem_path}" ]; then
+    _debug "PEM_PATH ${Le_Deploy_haproxy_pem_path} exists"
+  else
+    _err "PEM_PATH ${Le_Deploy_haproxy_pem_path} does not exist"
     return 1
   fi
-  _pem_full_path="$_pem_path/$_cdomain.pem"
-  _info "Full path to PEM $_pem_full_path"
 
-  # combine the key and fullchain into a single pem and install
-  cat "$_cfullchain" "$_ckey" >"$_pem_full_path"
-  chmod 600 "$_pem_full_path"
-  _info "Certificate successfully deployed"
+  # PEM_NAME is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}"
+  if [ -n "${DEPLOY_HAPROXY_PEM_NAME}" ]; then
+    Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME}"
+    _savedomainconf Le_Deploy_haproxy_pem_name "${Le_Deploy_haproxy_pem_name}"
+  elif [ -z "${Le_Deploy_haproxy_pem_name}" ]; then
+    Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}"
+  fi
+
+  # BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}"
+  if [ -n "${DEPLOY_HAPROXY_BUNDLE}" ]; then
+    Le_Deploy_haproxy_bundle="${DEPLOY_HAPROXY_BUNDLE}"
+    _savedomainconf Le_Deploy_haproxy_bundle "${Le_Deploy_haproxy_bundle}"
+  elif [ -z "${Le_Deploy_haproxy_bundle}" ]; then
+    Le_Deploy_haproxy_bundle="${DEPLOY_HAPROXY_BUNDLE_DEFAULT}"
+  fi
 
-  # restart HAProxy
-  _info "Run reload: $_reload"
-  if eval "$_reload"; then
-    _info "Reload success!"
-    return 0
+  # ISSUER is optional. If not provided then assume "${DEPLOY_HAPROXY_ISSUER_DEFAULT}"
+  if [ -n "${DEPLOY_HAPROXY_ISSUER}" ]; then
+    Le_Deploy_haproxy_issuer="${DEPLOY_HAPROXY_ISSUER}"
+    _savedomainconf Le_Deploy_haproxy_issuer "${Le_Deploy_haproxy_issuer}"
+  elif [ -z "${Le_Deploy_haproxy_issuer}" ]; then
+    Le_Deploy_haproxy_issuer="${DEPLOY_HAPROXY_ISSUER_DEFAULT}"
+  fi
+
+  # RELOAD is optional. If not provided then assume "${DEPLOY_HAPROXY_RELOAD_DEFAULT}"
+  if [ -n "${DEPLOY_HAPROXY_RELOAD}" ]; then
+    Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD}"
+    _savedomainconf Le_Deploy_haproxy_reload "${Le_Deploy_haproxy_reload}"
+  elif [ -z "${Le_Deploy_haproxy_reload}" ]; then
+    Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD_DEFAULT}"
+  fi
+
+  # Set the suffix depending if we are creating a bundle or not
+  if [ "${Le_Deploy_haproxy_bundle}" = "yes" ]; then
+    _info "Bundle creation requested"
+    # Initialise $Le_Keylength if its not already set
+    if [ -z "${Le_Keylength}" ]; then
+      Le_Keylength=""
+    fi
+    if _isEccKey "${Le_Keylength}"; then
+      _info "ECC key type detected"
+      _suffix=".ecdsa"
+    else
+      _info "RSA key type detected"
+      _suffix=".rsa"
+    fi
   else
-    _err "Reload error"
-    return 1
+    _suffix=""
+  fi
+  _debug _suffix "${_suffix}"
+
+  # Set variables for later
+  _pem="${Le_Deploy_haproxy_pem_path}/${Le_Deploy_haproxy_pem_name}${_suffix}"
+  _issuer="${_pem}.issuer"
+  _ocsp="${_pem}.ocsp"
+  _reload="${Le_Deploy_haproxy_reload}"
+
+  _info "Deploying PEM file"
+  # Create a temporary PEM file
+  _temppem="$(_mktemp)"
+  _debug _temppem "${_temppem}"
+  cat "${_ckey}" "${_ccert}" "${_cca}" >"${_temppem}"
+  _ret="$?"
+
+  # Check that we could create the temporary file
+  if [ "${_ret}" != "0" ]; then
+    _err "Error code ${_ret} returned during PEM file creation"
+    [ -f "${_temppem}" ] && rm -f "${_temppem}"
+    return ${_ret}
+  fi
+
+  # Move PEM file into place
+  _info "Moving new certificate into place"
+  _debug _pem "${_pem}"
+  cat "${_temppem}" >"${_pem}"
+  _ret=$?
+
+  # Clean up temp file
+  [ -f "${_temppem}" ] && rm -f "${_temppem}"
+
+  # Deal with any failure of moving PEM file into place
+  if [ "${_ret}" != "0" ]; then
+    _err "Error code ${_ret} returned while moving new certificate into place"
+    return ${_ret}
+  fi
+
+  # Update .issuer file if requested
+  if [ "${Le_Deploy_haproxy_issuer}" = "yes" ]; then
+    _info "Updating .issuer file"
+    _debug _issuer "${_issuer}"
+    cat "${_cca}" >"${_issuer}"
+    _ret="$?"
+
+    if [ "${_ret}" != "0" ]; then
+      _err "Error code ${_ret} returned while copying issuer/CA certificate into place"
+      return ${_ret}
+    fi
+  else
+    [ -f "${_issuer}" ] _err "Issuer file update not requested but .issuer file exists"
+  fi
+
+  # Update .ocsp file if certificate was requested with --ocsp/--ocsp-must-staple option
+  if [ -z "${Le_OCSP_Staple}" ]; then
+    Le_OCSP_Staple="0"
+  fi
+  if [ "${Le_OCSP_Staple}" = "1" ]; then
+    _info "Updating OCSP stapling info"
+    _debug _ocsp "${_ocsp}"
+    _info "Extracting OCSP URL"
+    _ocsp_url=$(openssl x509 -noout -ocsp_uri -in "${_pem}")
+    _debug _ocsp_url "${_ocsp_url}"
+
+    # Only process OCSP if URL was present
+    if [ "${_ocsp_url}" != "" ]; then
+      # Extract the hostname from the OCSP URL
+      _info "Extracting OCSP URL"
+      _ocsp_host=$(echo "${_ocsp_url}" | cut -d/ -f3)
+      _debug _ocsp_host "${_ocsp_host}"
+
+      # Only process the certificate if we have a .issuer file
+      if [ -r "${_issuer}" ]; then
+        # Check if issuer cert is also a root CA cert
+        _subjectdn=$(openssl x509 -in "${_issuer}" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
+        _debug _subjectdn "${_subjectdn}"
+        _issuerdn=$(openssl x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
+        _debug _issuerdn "${_issuerdn}"
+        _info "Requesting OCSP response"
+        # Request the OCSP response from the issuer and store it
+        if [ "${_subjectdn}" = "${_issuerdn}" ]; then
+          # If the issuer is a CA cert then our command line has "-CAfile" added
+          openssl ocsp \
+            -issuer "${_issuer}" \
+            -cert "${_pem}" \
+            -url "${_ocsp_url}" \
+            -header Host "${_ocsp_host}" \
+            -respout "${_ocsp}" \
+            -verify_other "${_issuer}" \
+            -no_nonce \
+            -CAfile "${_issuer}" \
+            | grep -q "${_pem}: good"
+          _ret=$?
+        else
+          # Issuer is not a root CA so no "-CAfile" option
+          openssl ocsp \
+            -issuer "${_issuer}" \
+            -cert "${_pem}" \
+            -url "${_ocsp_url}" \
+            -header Host "${_ocsp_host}" \
+            -respout "${_ocsp}" \
+            -verify_other "${_issuer}" \
+            -no_nonce \
+            | grep -q "${_pem}: good"
+          _ret=$?
+        fi
+      else
+        # Non fatal: No issuer file was present so no OCSP stapling file created
+        _err "OCSP stapling in use but no .issuer file was present"
+      fi
+    else
+      # Non fatal: No OCSP url was found int the certificate
+      _err "OCSP update requested but no OCSP URL was found in certificate"
+    fi
+
+    # Non fatal: Check return code of openssl command
+    if [ "${_ret}" != "0" ]; then
+      _err "Updating OCSP stapling failed with return code ${_ret}"
+    fi
+  else
+    # An OCSP file was already present but certificate did not have OCSP extension
+    if [ -f "${_ocsp}" ]; then
+      _err "OCSP was not requested but .ocsp file exists."
+      # Could remove the file at this step, although HAProxy just ignores it in this case
+      # rm -f "${_ocsp}" || _err "Problem removing stale .ocsp file"
+    fi
+  fi
+
+  # Reload HAProxy
+  _debug _reload "${_reload}"
+  eval "${_reload}"
+  _ret=$?
+  if [ "${_ret}" != "0" ]; then
+    _err "Error code ${_ret} during reload"
+    return ${_ret}
+  else
+    _info "Reload successful"
   fi
 
+  return 0
 }
index dfe6dcb7fdacf8c63572f174ea4f106dbd4ccfc1..903b96191977880d43352d2eb7ee2b172d7b0149 100644 (file)
@@ -119,7 +119,7 @@ _ddnss_rest() {
 
   # DDNSS uses GET to update domain info
   if [ "$method" = "GET" ]; then
-    response="$(_get "$url" | sed 's/<[^>]*>//g;/</N;//ba' | _tail_n 1)"
+    response="$(_get "$url" | sed 's/<[a-zA-Z\/][^>]*>//g' | _tail_n 1)"
   else
     _err "Unsupported method"
     return 1
diff --git a/notify/mail.sh b/notify/mail.sh
new file mode 100644 (file)
index 0000000..3dfef0b
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/env sh
+
+# support local mail app
+
+mail_send() {
+  _subject="$1"
+  _content="$2"
+  _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
+  _debug "_subject" "$_subject"
+  _debug "_content" "$_content"
+  _debug "_statusCode" "$_statusCode"
+
+  _err "Not implemented yet."
+  return 1
+}
diff --git a/notify/mailgun.sh b/notify/mailgun.sh
new file mode 100644 (file)
index 0000000..1689a0b
--- /dev/null
@@ -0,0 +1,123 @@
+#!/usr/bin/env sh
+
+#Support mailgun.com api
+
+#MAILGUN_API_KEY="xxxx"
+#MAILGUN_TO="yyyy@gmail.com"
+
+#MAILGUN_REGION="us|eu"          #optional, use "us" as default
+#MAILGUN_API_DOMAIN="xxxxxx.com"  #optional, use the default sandbox domain
+#MAILGUN_FROM="xxx@xxxxx.com"    #optional, use the default sendbox account
+
+_MAILGUN_BASE="https://api.mailgun.net/v3"
+
+# subject  content statusCode
+mailgun_send() {
+  _subject="$1"
+  _content="$2"
+  _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
+  _debug "_statusCode" "$_statusCode"
+
+  MAILGUN_API_KEY="${MAILGUN_API_KEY:-$(_readaccountconf_mutable MAILGUN_API_KEY)}"
+  if [ -z "$MAILGUN_API_KEY" ]; then
+    MAILGUN_API_KEY=""
+    _err "You didn't specify a mailgun api key MAILGUN_API_KEY yet ."
+    _err "You can get yours from here https://mailgun.com"
+    return 1
+  fi
+  _saveaccountconf_mutable MAILGUN_API_KEY "$MAILGUN_API_KEY"
+
+  MAILGUN_REGION="${MAILGUN_REGION:-$(_readaccountconf_mutable MAILGUN_REGION)}"
+  if [ -z "$MAILGUN_REGION" ]; then
+    MAILGUN_REGION=""
+    _info "The MAILGUN_REGION is not set, so use the default us region."
+    _MAILGUN_BASE="https://api.mailgun.net/v3"
+  else
+    _saveaccountconf_mutable MAILGUN_REGION "$MAILGUN_REGION"
+    _MAILGUN_BASE="https://api.eu.mailgun.net/v3"
+  fi
+
+  MAILGUN_TO="${MAILGUN_TO:-$(_readaccountconf_mutable MAILGUN_TO)}"
+  if [ -z "$MAILGUN_TO" ]; then
+    MAILGUN_TO=""
+    _err "You didn't specify an email to MAILGUN_TO receive messages."
+    return 1
+  fi
+  _saveaccountconf_mutable MAILGUN_TO "$MAILGUN_TO"
+
+  MAILGUN_API_DOMAIN="${MAILGUN_API_DOMAIN:-$(_readaccountconf_mutable MAILGUN_API_DOMAIN)}"
+  if [ -z "$MAILGUN_API_DOMAIN" ]; then
+    _info "The MAILGUN_API_DOMAIN is not set, try to get the default sending sandbox domain for you."
+    if ! _mailgun_rest GET "/domains"; then
+      _err "Can not get sandbox domain."
+      return 1
+    fi
+    _sendboxDomain="$(echo "$response" | _egrep_o '"name": *"sandbox.*.mailgun.org"' | cut -d : -f 2 | tr -d '" ')"
+    _debug _sendboxDomain "$_sendboxDomain"
+    MAILGUN_API_DOMAIN="$_sendboxDomain"
+    if [ -z "$MAILGUN_API_DOMAIN" ]; then
+      _err "Can not get sandbox domain for MAILGUN_API_DOMAIN"
+      return 1
+    fi
+
+    _info "$(__green "When using sandbox domain, you must verify your email first.")"
+    #todo: add recepient
+  fi
+  if [ -z "$MAILGUN_API_DOMAIN" ]; then
+    _err "Can not get MAILGUN_API_DOMAIN"
+    return 1
+  fi
+  _saveaccountconf_mutable MAILGUN_API_DOMAIN "$MAILGUN_API_DOMAIN"
+
+  MAILGUN_FROM="${MAILGUN_FROM:-$(_readaccountconf_mutable MAILGUN_FROM)}"
+  if [ -z "$MAILGUN_FROM" ]; then
+    MAILGUN_FROM="$PROJECT_NAME@$MAILGUN_API_DOMAIN"
+    _info "The MAILGUN_FROM is not set, so use the default value: $MAILGUN_FROM"
+  else
+    _debug MAILGUN_FROM "$MAILGUN_FROM"
+    _saveaccountconf_mutable MAILGUN_FROM "$MAILGUN_FROM"
+  fi
+
+  #send from url
+  _msg="/$MAILGUN_API_DOMAIN/messages?from=$(printf "%s" "$MAILGUN_FROM" | _url_encode)&to=$(printf "%s" "$MAILGUN_TO" | _url_encode)&subject=$(printf "%s" "$_subject" | _url_encode)&text=$(printf "%s" "$_content" | _url_encode)"
+  _debug "_msg" "$_msg"
+  _mailgun_rest POST "$_msg"
+  if _contains "$response" "Queued. Thank you."; then
+    _info "mailgun send success."
+    return 0
+  else
+    _err "mailgun send error"
+    _err "$response"
+    return 1
+  fi
+
+}
+
+# method uri  data
+_mailgun_rest() {
+  _method="$1"
+  _mguri="$2"
+  _mgdata="$3"
+  _debug _mguri "$_mguri"
+  _mgurl="$_MAILGUN_BASE$_mguri"
+  _debug _mgurl "$_mgurl"
+
+  _auth="$(printf "%s" "api:$MAILGUN_API_KEY" | _base64)"
+  export _H1="Authorization: Basic $_auth"
+  export _H2="Content-Type: application/json"
+
+  if [ "$_method" = "GET" ]; then
+    response="$(_get "$_mgurl")"
+  else
+    _debug _mgdata "$_mgdata"
+    response="$(_post "$_mgdata" "$_mgurl" "" "$_method")"
+  fi
+  if [ "$?" != "0" ]; then
+    _err "Error: $_mguri"
+    _err "$response"
+    return 1
+  fi
+  _debug2 response "$response"
+  return 0
+
+}
diff --git a/notify/pop.sh b/notify/pop.sh
new file mode 100644 (file)
index 0000000..f118d79
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/env sh
+
+# support pop
+
+pop_send() {
+  _subject="$1"
+  _content="$2"
+  _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
+  _debug "_subject" "$_subject"
+  _debug "_content" "$_content"
+  _debug "_statusCode" "$_statusCode"
+
+  _err "Not implemented yet."
+  return 1
+}
diff --git a/notify/sendgrid.sh b/notify/sendgrid.sh
new file mode 100644 (file)
index 0000000..5c5bfdb
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/env sh
+
+#Support SENDGRID.com api
+
+#SENDGRID_API_KEY=""
+#SENDGRID_TO="xxxx@xxx.com"
+#SENDGRID_FROM="xxxx@cccc.com"
+
+sendgrid_send() {
+  _subject="$1"
+  _content="$2"
+  _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
+  _debug "_statusCode" "$_statusCode"
+
+  SENDGRID_API_KEY="${SENDGRID_API_KEY:-$(_readaccountconf_mutable SENDGRID_API_KEY)}"
+  if [ -z "$SENDGRID_API_KEY" ]; then
+    SENDGRID_API_KEY=""
+    _err "You didn't specify a sendgrid api key SENDGRID_API_KEY yet ."
+    _err "You can get yours from here https://sendgrid.com"
+    return 1
+  fi
+  _saveaccountconf_mutable SENDGRID_API_KEY "$SENDGRID_API_KEY"
+
+  SENDGRID_TO="${SENDGRID_TO:-$(_readaccountconf_mutable SENDGRID_TO)}"
+  if [ -z "$SENDGRID_TO" ]; then
+    SENDGRID_TO=""
+    _err "You didn't specify an email to SENDGRID_TO receive messages."
+    return 1
+  fi
+  _saveaccountconf_mutable SENDGRID_TO "$SENDGRID_TO"
+
+  SENDGRID_FROM="${SENDGRID_FROM:-$(_readaccountconf_mutable SENDGRID_FROM)}"
+  if [ -z "$SENDGRID_FROM" ]; then
+    SENDGRID_FROM=""
+    _err "You didn't specify an email to SENDGRID_FROM receive messages."
+    return 1
+  fi
+  _saveaccountconf_mutable SENDGRID_FROM "$SENDGRID_FROM"
+
+  export _H1="Authorization: Bearer $SENDGRID_API_KEY"
+  export _H2="Content-Type: application/json"
+
+  _content="$(echo "$_content" | _json_encode)"
+  _data="{\"personalizations\": [{\"to\": [{\"email\": \"$SENDGRID_TO\"}]}],\"from\": {\"email\": \"$SENDGRID_FROM\"},\"subject\": \"$_subject\",\"content\": [{\"type\": \"text/plain\", \"value\": \"$_content\"}]}"
+  response="" #just make shellcheck happy
+  if _post "$_data" "https://api.sendgrid.com/v3/mail/send"; then
+    if [ -z "$response" ]; then
+      _info "sendgrid send sccess."
+      return 0
+    fi
+  fi
+  _err "sendgrid send error."
+  _err "$response"
+  return 1
+
+}
diff --git a/notify/smtp.sh b/notify/smtp.sh
new file mode 100644 (file)
index 0000000..6aa37ca
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/env sh
+
+# support smtp
+
+smtp_send() {
+  _subject="$1"
+  _content="$2"
+  _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped
+  _debug "_subject" "$_subject"
+  _debug "_content" "$_content"
+  _debug "_statusCode" "$_statusCode"
+
+  _err "Not implemented yet."
+  return 1
+}