diff --git a/security/acme-client/Makefile b/security/acme-client/Makefile index c33d6e203..1e9323d3f 100644 --- a/security/acme-client/Makefile +++ b/security/acme-client/Makefile @@ -2,5 +2,6 @@ PLUGIN_NAME= acme-client PLUGIN_VERSION= 1.7 PLUGIN_COMMENT= Let's Encrypt client PLUGIN_MAINTAINER= opnsense@moov.de +PLUGIN_DEPENDS= acme.sh .include "../../Mk/plugins.mk" diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/acme.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/acme.sh deleted file mode 100755 index 41474aba1..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/acme.sh +++ /dev/null @@ -1,5485 +0,0 @@ -#!/usr/bin/env sh - -VER=2.6.7 - -PROJECT_NAME="acme.sh" - -PROJECT_ENTRY="acme.sh" - -PROJECT="https://github.com/Neilpang/$PROJECT_NAME" - -DEFAULT_INSTALL_HOME="$HOME/.$PROJECT_NAME" -_SCRIPT_="$0" - -_SUB_FOLDERS="dnsapi deploy" - -DEFAULT_CA="https://acme-v01.api.letsencrypt.org" -DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" - -DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" -DEFAULT_ACCOUNT_EMAIL="" - -DEFAULT_ACCOUNT_KEY_LENGTH=2048 -DEFAULT_DOMAIN_KEY_LENGTH=2048 - -DEFAULT_OPENSSL_BIN="openssl" - -STAGE_CA="https://acme-staging.api.letsencrypt.org" - -VTYPE_HTTP="http-01" -VTYPE_DNS="dns-01" -VTYPE_TLS="tls-sni-01" -#VTYPE_TLS2="tls-sni-02" - -LOCAL_ANY_ADDRESS="0.0.0.0" - -MAX_RENEW=60 - -DEFAULT_DNS_SLEEP=120 - -NO_VALUE="no" - -W_TLS="tls" - -MODE_STATELESS="stateless" - -STATE_VERIFIED="verified_ok" - -NGINX="nginx:" -NGINX_START="#ACME_NGINX_START" -NGINX_END="#ACME_NGINX_END" - -BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" -END_CSR="-----END CERTIFICATE REQUEST-----" - -BEGIN_CERT="-----BEGIN CERTIFICATE-----" -END_CERT="-----END CERTIFICATE-----" - -RENEW_SKIP=2 - -ECC_SEP="_" -ECC_SUFFIX="${ECC_SEP}ecc" - -LOG_LEVEL_1=1 -LOG_LEVEL_2=2 -LOG_LEVEL_3=3 -DEFAULT_LOG_LEVEL="$LOG_LEVEL_1" - -DEBUG_LEVEL_1=1 -DEBUG_LEVEL_2=2 -DEBUG_LEVEL_3=3 -DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1 -DEBUG_LEVEL_NONE=0 - -HIDDEN_VALUE="[hidden](please add '--output-insecure' to see this value)" - -SYSLOG_ERROR="user.error" -SYSLOG_INFO="user.info" -SYSLOG_DEBUG="user.debug" - -#error -SYSLOG_LEVEL_ERROR=3 -#info -SYSLOG_LEVEL_INFO=6 -#debug -SYSLOG_LEVEL_DEBUG=7 -#debug2 -SYSLOG_LEVEL_DEBUG_2=8 -#debug3 -SYSLOG_LEVEL_DEBUG_3=9 - -SYSLOG_LEVEL_DEFAULT=$SYSLOG_LEVEL_ERROR -#none -SYSLOG_LEVEL_NONE=0 - -_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" - -_STATELESS_WIKI="https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode" - -__INTERACTIVE="" -if [ -t 1 ]; then - __INTERACTIVE="1" -fi - -__green() { - if [ "$__INTERACTIVE" ]; then - printf '\033[1;31;32m' - fi - printf -- "$1" - if [ "$__INTERACTIVE" ]; then - printf '\033[0m' - fi -} - -__red() { - if [ "$__INTERACTIVE" ]; then - printf '\033[1;31;40m' - fi - printf -- "$1" - if [ "$__INTERACTIVE" ]; then - printf '\033[0m' - fi -} - -_printargs() { - if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then - printf -- "%s" "[$(date)] " - fi - if [ -z "$2" ]; then - printf -- "%s" "$1" - else - printf -- "%s" "$1='$2'" - fi - printf "\n" -} - -_dlg_versions() { - echo "Diagnosis versions: " - echo "openssl:$ACME_OPENSSL_BIN" - if _exists "$ACME_OPENSSL_BIN"; then - $ACME_OPENSSL_BIN version 2>&1 - else - echo "$ACME_OPENSSL_BIN doesn't exists." - fi - - echo "apache:" - if [ "$_APACHECTL" ] && _exists "$_APACHECTL"; then - $_APACHECTL -V 2>&1 - else - echo "apache doesn't exists." - fi - - echo "nc:" - if _exists "nc"; then - nc -h 2>&1 - else - _debug "nc doesn't exists." - fi -} - -#class -_syslog() { - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" = "$SYSLOG_LEVEL_NONE" ]; then - return - fi - _logclass="$1" - shift - logger -i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1 -} - -_log() { - [ -z "$LOG_FILE" ] && return - _printargs "$@" >>"$LOG_FILE" -} - -_info() { - _log "$@" - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_INFO" ]; then - _syslog "$SYSLOG_INFO" "$@" - fi - _printargs "$@" -} - -_err() { - _syslog "$SYSLOG_ERROR" "$@" - _log "$@" - if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then - printf -- "%s" "[$(date)] " >&2 - fi - if [ -z "$2" ]; then - __red "$1" >&2 - else - __red "$1='$2'" >&2 - fi - printf "\n" >&2 - return 1 -} - -_usage() { - __red "$@" >&2 - printf "\n" >&2 -} - -_debug() { - if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then - _log "$@" - fi - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then - _syslog "$SYSLOG_DEBUG" "$@" - fi - if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then - _printargs "$@" >&2 - fi -} - -#output the sensitive messages -_secure_debug() { - if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then - if [ "$OUTPUT_INSECURE" = "1" ]; then - _log "$@" - else - _log "$1" "$HIDDEN_VALUE" - fi - fi - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then - _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" - fi - if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then - if [ "$OUTPUT_INSECURE" = "1" ]; then - _printargs "$@" >&2 - else - _printargs "$1" "$HIDDEN_VALUE" >&2 - fi - fi -} - -_debug2() { - if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then - _log "$@" - fi - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then - _syslog "$SYSLOG_DEBUG" "$@" - fi - if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then - _printargs "$@" >&2 - fi -} - -_secure_debug2() { - if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then - if [ "$OUTPUT_INSECURE" = "1" ]; then - _log "$@" - else - _log "$1" "$HIDDEN_VALUE" - fi - fi - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then - _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" - fi - if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then - if [ "$OUTPUT_INSECURE" = "1" ]; then - _printargs "$@" >&2 - else - _printargs "$1" "$HIDDEN_VALUE" >&2 - fi - fi -} - -_debug3() { - if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then - _log "$@" - fi - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then - _syslog "$SYSLOG_DEBUG" "$@" - fi - if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then - _printargs "$@" >&2 - fi -} - -_secure_debug3() { - if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then - if [ "$OUTPUT_INSECURE" = "1" ]; then - _log "$@" - else - _log "$1" "$HIDDEN_VALUE" - fi - fi - if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then - _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" - fi - if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then - if [ "$OUTPUT_INSECURE" = "1" ]; then - _printargs "$@" >&2 - else - _printargs "$1" "$HIDDEN_VALUE" >&2 - fi - fi -} - -_upper_case() { - # shellcheck disable=SC2018,SC2019 - tr 'a-z' 'A-Z' -} - -_lower_case() { - # shellcheck disable=SC2018,SC2019 - tr 'A-Z' 'a-z' -} - -_startswith() { - _str="$1" - _sub="$2" - echo "$_str" | grep "^$_sub" >/dev/null 2>&1 -} - -_endswith() { - _str="$1" - _sub="$2" - echo "$_str" | grep -- "$_sub\$" >/dev/null 2>&1 -} - -_contains() { - _str="$1" - _sub="$2" - echo "$_str" | grep -- "$_sub" >/dev/null 2>&1 -} - -_hasfield() { - _str="$1" - _field="$2" - _sep="$3" - if [ -z "$_field" ]; then - _usage "Usage: str field [sep]" - return 1 - fi - - if [ -z "$_sep" ]; then - _sep="," - fi - - for f in $(echo "$_str" | tr ',' ' '); do - if [ "$f" = "$_field" ]; then - _debug2 "'$_str' contains '$_field'" - return 0 #contains ok - fi - done - _debug2 "'$_str' does not contain '$_field'" - return 1 #not contains -} - -_getfield() { - _str="$1" - _findex="$2" - _sep="$3" - - if [ -z "$_findex" ]; then - _usage "Usage: str field [sep]" - return 1 - fi - - if [ -z "$_sep" ]; then - _sep="," - fi - - _ffi="$_findex" - while [ "$_ffi" -gt "0" ]; do - _fv="$(echo "$_str" | cut -d "$_sep" -f "$_ffi")" - if [ "$_fv" ]; then - printf -- "%s" "$_fv" - return 0 - fi - _ffi="$(_math "$_ffi" - 1)" - done - - printf -- "%s" "$_str" - -} - -_exists() { - cmd="$1" - if [ -z "$cmd" ]; then - _usage "Usage: _exists cmd" - return 1 - fi - - if eval type type >/dev/null 2>&1; then - eval type "$cmd" >/dev/null 2>&1 - elif command >/dev/null 2>&1; then - command -v "$cmd" >/dev/null 2>&1 - else - which "$cmd" >/dev/null 2>&1 - fi - ret="$?" - _debug3 "$cmd exists=$ret" - return $ret -} - -#a + b -_math() { - _m_opts="$@" - printf "%s" "$(($_m_opts))" -} - -_h_char_2_dec() { - _ch=$1 - case "${_ch}" in - a | A) - printf "10" - ;; - b | B) - printf "11" - ;; - c | C) - printf "12" - ;; - d | D) - printf "13" - ;; - e | E) - printf "14" - ;; - f | F) - printf "15" - ;; - *) - printf "%s" "$_ch" - ;; - esac - -} - -_URGLY_PRINTF="" -if [ "$(printf '\x41')" != 'A' ]; then - _URGLY_PRINTF=1 -fi - -_h2b() { - hex=$(cat) - i=1 - j=2 - - _debug3 _URGLY_PRINTF "$_URGLY_PRINTF" - while true; do - if [ -z "$_URGLY_PRINTF" ]; then - h="$(printf "%s" "$hex" | cut -c $i-$j)" - if [ -z "$h" ]; then - break - fi - printf "\x$h%s" - else - ic="$(printf "%s" "$hex" | cut -c $i)" - jc="$(printf "%s" "$hex" | cut -c $j)" - if [ -z "$ic$jc" ]; then - break - fi - ic="$(_h_char_2_dec "$ic")" - jc="$(_h_char_2_dec "$jc")" - printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s" - fi - - i="$(_math "$i" + 2)" - j="$(_math "$j" + 2)" - - done -} - -_is_solaris() { - _contains "${__OS__:=$(uname -a)}" "solaris" || _contains "${__OS__:=$(uname -a)}" "SunOS" -} - -#_ascii_hex str -#this can only process ascii chars, should only be used when od command is missing as a backup way. -_ascii_hex() { - _debug2 "Using _ascii_hex" - _str="$1" - _str_len=${#_str} - _h_i=1 - while [ "$_h_i" -le "$_str_len" ]; do - _str_c="$(printf "%s" "$_str" | cut -c "$_h_i")" - printf " %02x" "'$_str_c" - _h_i="$(_math "$_h_i" + 1)" - done -} - -#stdin output hexstr splited by one space -#input:"abc" -#output: " 61 62 63" -_hex_dump() { - if _exists od; then - od -A n -v -t x1 | tr -s " " | sed 's/ $//' | tr -d "\r\t\n" - elif _exists hexdump; then - _debug3 "using hexdump" - hexdump -v -e '/1 ""' -e '/1 " %02x" ""' - elif _exists xxd; then - _debug3 "using xxd" - xxd -ps -c 20 -i | sed "s/ 0x/ /g" | tr -d ",\n" | tr -s " " - else - _debug3 "using _ascii_hex" - str=$(cat) - _ascii_hex "$str" - fi -} - -#url encode, no-preserved chars -#A B C D E F G H I J K L M N O P Q R S T U V W X Y Z -#41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a - -#a b c d e f g h i j k l m n o p q r s t u v w x y z -#61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a - -#0 1 2 3 4 5 6 7 8 9 - _ . ~ -#30 31 32 33 34 35 36 37 38 39 2d 5f 2e 7e - -#stdin stdout -_url_encode() { - _hex_str=$(_hex_dump) - _debug3 "_url_encode" - _debug3 "_hex_str" "$_hex_str" - for _hex_code in $_hex_str; do - #upper case - case "${_hex_code}" in - "41") - printf "%s" "A" - ;; - "42") - printf "%s" "B" - ;; - "43") - printf "%s" "C" - ;; - "44") - printf "%s" "D" - ;; - "45") - printf "%s" "E" - ;; - "46") - printf "%s" "F" - ;; - "47") - printf "%s" "G" - ;; - "48") - printf "%s" "H" - ;; - "49") - printf "%s" "I" - ;; - "4a") - printf "%s" "J" - ;; - "4b") - printf "%s" "K" - ;; - "4c") - printf "%s" "L" - ;; - "4d") - printf "%s" "M" - ;; - "4e") - printf "%s" "N" - ;; - "4f") - printf "%s" "O" - ;; - "50") - printf "%s" "P" - ;; - "51") - printf "%s" "Q" - ;; - "52") - printf "%s" "R" - ;; - "53") - printf "%s" "S" - ;; - "54") - printf "%s" "T" - ;; - "55") - printf "%s" "U" - ;; - "56") - printf "%s" "V" - ;; - "57") - printf "%s" "W" - ;; - "58") - printf "%s" "X" - ;; - "59") - printf "%s" "Y" - ;; - "5a") - printf "%s" "Z" - ;; - - #lower case - "61") - printf "%s" "a" - ;; - "62") - printf "%s" "b" - ;; - "63") - printf "%s" "c" - ;; - "64") - printf "%s" "d" - ;; - "65") - printf "%s" "e" - ;; - "66") - printf "%s" "f" - ;; - "67") - printf "%s" "g" - ;; - "68") - printf "%s" "h" - ;; - "69") - printf "%s" "i" - ;; - "6a") - printf "%s" "j" - ;; - "6b") - printf "%s" "k" - ;; - "6c") - printf "%s" "l" - ;; - "6d") - printf "%s" "m" - ;; - "6e") - printf "%s" "n" - ;; - "6f") - printf "%s" "o" - ;; - "70") - printf "%s" "p" - ;; - "71") - printf "%s" "q" - ;; - "72") - printf "%s" "r" - ;; - "73") - printf "%s" "s" - ;; - "74") - printf "%s" "t" - ;; - "75") - printf "%s" "u" - ;; - "76") - printf "%s" "v" - ;; - "77") - printf "%s" "w" - ;; - "78") - printf "%s" "x" - ;; - "79") - printf "%s" "y" - ;; - "7a") - printf "%s" "z" - ;; - #numbers - "30") - printf "%s" "0" - ;; - "31") - printf "%s" "1" - ;; - "32") - printf "%s" "2" - ;; - "33") - printf "%s" "3" - ;; - "34") - printf "%s" "4" - ;; - "35") - printf "%s" "5" - ;; - "36") - printf "%s" "6" - ;; - "37") - printf "%s" "7" - ;; - "38") - printf "%s" "8" - ;; - "39") - printf "%s" "9" - ;; - "2d") - printf "%s" "-" - ;; - "5f") - printf "%s" "_" - ;; - "2e") - printf "%s" "." - ;; - "7e") - printf "%s" "~" - ;; - #other hex - *) - printf '%%%s' "$_hex_code" - ;; - esac - done -} - -#options file -_sed_i() { - options="$1" - filename="$2" - if [ -z "$filename" ]; then - _usage "Usage:_sed_i options filename" - return 1 - fi - _debug2 options "$options" - if sed -h 2>&1 | grep "\-i\[SUFFIX]" >/dev/null 2>&1; then - _debug "Using sed -i" - sed -i "$options" "$filename" - else - _debug "No -i support in sed" - text="$(cat "$filename")" - echo "$text" | sed "$options" >"$filename" - fi -} - -_egrep_o() { - if ! egrep -o "$1" 2>/dev/null; then - sed -n 's/.*\('"$1"'\).*/\1/p' - fi -} - -#Usage: file startline endline -_getfile() { - filename="$1" - startline="$2" - endline="$3" - if [ -z "$endline" ]; then - _usage "Usage: file startline endline" - return 1 - fi - - i="$(grep -n -- "$startline" "$filename" | cut -d : -f 1)" - if [ -z "$i" ]; then - _err "Can not find start line: $startline" - return 1 - fi - i="$(_math "$i" + 1)" - _debug i "$i" - - j="$(grep -n -- "$endline" "$filename" | cut -d : -f 1)" - if [ -z "$j" ]; then - _err "Can not find end line: $endline" - return 1 - fi - j="$(_math "$j" - 1)" - _debug j "$j" - - sed -n "$i,${j}p" "$filename" - -} - -#Usage: multiline -_base64() { - [ "" ] #urgly - if [ "$1" ]; then - _debug3 "base64 multiline:'$1'" - $ACME_OPENSSL_BIN base64 -e - else - _debug3 "base64 single line." - $ACME_OPENSSL_BIN base64 -e | tr -d '\r\n' - fi -} - -#Usage: multiline -_dbase64() { - if [ "$1" ]; then - $ACME_OPENSSL_BIN base64 -d -A - else - $ACME_OPENSSL_BIN base64 -d - fi -} - -#Usage: hashalg [outputhex] -#Output Base64-encoded digest -_digest() { - alg="$1" - if [ -z "$alg" ]; then - _usage "Usage: _digest hashalg" - return 1 - fi - - outputhex="$2" - - if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then - if [ "$outputhex" ]; then - $ACME_OPENSSL_BIN dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' - else - $ACME_OPENSSL_BIN dgst -"$alg" -binary | _base64 - fi - else - _err "$alg is not supported yet" - return 1 - fi - -} - -#Usage: hashalg secret_hex [outputhex] -#Output binary hmac -_hmac() { - alg="$1" - secret_hex="$2" - outputhex="$3" - - if [ -z "$secret_hex" ]; then - _usage "Usage: _hmac hashalg secret [outputhex]" - return 1 - fi - - if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then - if [ "$outputhex" ]; then - ($ACME_OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || $ACME_OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' ' - else - $ACME_OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || $ACME_OPENSSL_BIN dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary - fi - else - _err "$alg is not supported yet" - return 1 - fi - -} - -#Usage: keyfile hashalg -#Output: Base64-encoded signature value -_sign() { - keyfile="$1" - alg="$2" - if [ -z "$alg" ]; then - _usage "Usage: _sign keyfile hashalg" - return 1 - fi - - _sign_openssl="$ACME_OPENSSL_BIN dgst -sign $keyfile " - if [ "$alg" = "sha256" ]; then - _sign_openssl="$_sign_openssl -$alg" - else - _err "$alg is not supported yet" - return 1 - fi - - if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then - $_sign_openssl | _base64 - elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then - if ! _signedECText="$($_sign_openssl | $ACME_OPENSSL_BIN asn1parse -inform DER)"; then - _err "Sign failed: $_sign_openssl" - _err "Key file: $keyfile" - _err "Key content:$(wc -l <"$keyfile") lises" - return 1 - fi - _debug3 "_signedECText" "$_signedECText" - _ec_r="$(echo "$_signedECText" | _head_n 2 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")" - _debug3 "_ec_r" "$_ec_r" - _ec_s="$(echo "$_signedECText" | _head_n 3 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")" - _debug3 "_ec_s" "$_ec_s" - printf "%s" "$_ec_r$_ec_s" | _h2b | _base64 - else - _err "Unknown key file format." - return 1 - fi - -} - -#keylength -_isEccKey() { - _length="$1" - - if [ -z "$_length" ]; then - return 1 - fi - - [ "$_length" != "1024" ] \ - && [ "$_length" != "2048" ] \ - && [ "$_length" != "3072" ] \ - && [ "$_length" != "4096" ] \ - && [ "$_length" != "8192" ] -} - -# _createkey 2048|ec-256 file -_createkey() { - length="$1" - f="$2" - _debug2 "_createkey for file:$f" - eccname="$length" - if _startswith "$length" "ec-"; then - length=$(printf "%s" "$length" | cut -d '-' -f 2-100) - - if [ "$length" = "256" ]; then - eccname="prime256v1" - fi - if [ "$length" = "384" ]; then - eccname="secp384r1" - fi - if [ "$length" = "521" ]; then - eccname="secp521r1" - fi - - fi - - if [ -z "$length" ]; then - length=2048 - fi - - _debug "Use length $length" - - if ! touch "$f" >/dev/null 2>&1; then - _f_path="$(dirname "$f")" - _debug _f_path "$_f_path" - if ! mkdir -p "$_f_path"; then - _err "Can not create path: $_f_path" - return 1 - fi - fi - - if _isEccKey "$length"; then - _debug "Using ec name: $eccname" - $ACME_OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f" - else - _debug "Using RSA: $length" - $ACME_OPENSSL_BIN genrsa "$length" 2>/dev/null >"$f" - fi - - if [ "$?" != "0" ]; then - _err "Create key error." - return 1 - fi -} - -#domain -_is_idn() { - _is_idn_d="$1" - _debug2 _is_idn_d "$_is_idn_d" - _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '.,-') - _debug2 _idn_temp "$_idn_temp" - [ "$_idn_temp" ] -} - -#aa.com -#aa.com,bb.com,cc.com -_idn() { - __idn_d="$1" - if ! _is_idn "$__idn_d"; then - printf "%s" "$__idn_d" - return 0 - fi - - if _exists idn; then - if _contains "$__idn_d" ','; then - _i_first="1" - for f in $(echo "$__idn_d" | tr ',' ' '); do - [ -z "$f" ] && continue - if [ -z "$_i_first" ]; then - printf "%s" "," - else - _i_first="" - fi - idn --quiet "$f" | tr -d "\r\n" - done - else - idn "$__idn_d" | tr -d "\r\n" - fi - else - _err "Please install idn to process IDN names." - fi -} - -#_createcsr cn san_list keyfile csrfile conf -_createcsr() { - _debug _createcsr - domain="$1" - domainlist="$2" - csrkey="$3" - csr="$4" - csrconf="$5" - _debug2 domain "$domain" - _debug2 domainlist "$domainlist" - _debug2 csrkey "$csrkey" - _debug2 csr "$csr" - _debug2 csrconf "$csrconf" - - printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" >"$csrconf" - - if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then - #single domain - _info "Single domain" "$domain" - else - domainlist="$(_idn "$domainlist")" - _debug2 domainlist "$domainlist" - if _contains "$domainlist" ","; then - alt="DNS:$(echo "$domainlist" | sed "s/,/,DNS:/g")" - else - alt="DNS:$domainlist" - fi - #multi - _info "Multi domain" "$alt" - printf -- "\nsubjectAltName=$alt" >>"$csrconf" - fi - if [ "$Le_OCSP_Staple" ] || [ "$Le_OCSP_Stable" ]; then - _savedomainconf Le_OCSP_Staple "$Le_OCSP_Staple" - _cleardomainconf Le_OCSP_Stable - printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf" - fi - - _csr_cn="$(_idn "$domain")" - _debug2 _csr_cn "$_csr_cn" - if _contains "$(uname -a)" "MINGW"; then - $ACME_OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" - else - $ACME_OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" - fi -} - -#_signcsr key csr conf cert -_signcsr() { - key="$1" - csr="$2" - conf="$3" - cert="$4" - _debug "_signcsr" - - _msg="$($ACME_OPENSSL_BIN x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" - _ret="$?" - _debug "$_msg" - return $_ret -} - -#_csrfile -_readSubjectFromCSR() { - _csrfile="$1" - if [ -z "$_csrfile" ]; then - _usage "_readSubjectFromCSR mycsr.csr" - return 1 - fi - $ACME_OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n' -} - -#_csrfile -#echo comma separated domain list -_readSubjectAltNamesFromCSR() { - _csrfile="$1" - if [ -z "$_csrfile" ]; then - _usage "_readSubjectAltNamesFromCSR mycsr.csr" - return 1 - fi - - _csrsubj="$(_readSubjectFromCSR "$_csrfile")" - _debug _csrsubj "$_csrsubj" - - _dnsAltnames="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" - _debug _dnsAltnames "$_dnsAltnames" - - if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then - _debug "AltNames contains subject" - _dnsAltnames="$(printf "%s" "$_dnsAltnames," | sed "s/DNS:$_csrsubj,//g")" - else - _debug "AltNames doesn't contain subject" - fi - - printf "%s" "$_dnsAltnames" | sed "s/DNS://g" -} - -#_csrfile -_readKeyLengthFromCSR() { - _csrfile="$1" - if [ -z "$_csrfile" ]; then - _usage "_readKeyLengthFromCSR mycsr.csr" - return 1 - fi - - _outcsr="$($ACME_OPENSSL_BIN req -noout -text -in "$_csrfile")" - if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then - _debug "ECC CSR" - echo "$_outcsr" | _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 - fi -} - -_ss() { - _port="$1" - - if _exists "ss"; then - _debug "Using: ss" - ss -ntpl | grep ":$_port " - return 0 - fi - - if _exists "netstat"; then - _debug "Using: netstat" - if netstat -h 2>&1 | grep "\-p proto" >/dev/null; then - #for windows version netstat tool - netstat -an -p tcp | grep "LISTENING" | grep ":$_port " - else - if netstat -help 2>&1 | grep "\-p protocol" >/dev/null; then - netstat -an -p tcp | grep LISTEN | grep ":$_port " - elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then - #for solaris - netstat -an -P tcp | grep "\.$_port " | grep "LISTEN" - else - netstat -ntpl | grep ":$_port " - fi - fi - return 0 - fi - - return 1 -} - -#domain [password] [isEcc] -toPkcs() { - domain="$1" - pfxPassword="$2" - if [ -z "$domain" ]; then - _usage "Usage: $PROJECT_ENTRY --toPkcs -d domain [--password pfx-password]" - return 1 - fi - - _isEcc="$3" - - _initpath "$domain" "$_isEcc" - - if [ "$pfxPassword" ]; then - $ACME_OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword" - else - $ACME_OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" - fi - - if [ "$?" = "0" ]; then - _info "Success, Pfx is exported to: $CERT_PFX_PATH" - fi - -} - -#domain [isEcc] -toPkcs8() { - domain="$1" - - if [ -z "$domain" ]; then - _usage "Usage: $PROJECT_ENTRY --toPkcs8 -d domain [--ecc]" - return 1 - fi - - _isEcc="$2" - - _initpath "$domain" "$_isEcc" - - $ACME_OPENSSL_BIN pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in "$CERT_KEY_PATH" -out "$CERT_PKCS8_PATH" - - if [ "$?" = "0" ]; then - _info "Success, $CERT_PKCS8_PATH" - fi - -} - -#[2048] -createAccountKey() { - _info "Creating account key" - if [ -z "$1" ]; then - _usage "Usage: $PROJECT_ENTRY --createAccountKey --accountkeylength 2048" - return - fi - - length=$1 - _create_account_key "$length" - -} - -_create_account_key() { - - length=$1 - - if [ -z "$length" ] || [ "$length" = "$NO_VALUE" ]; then - _debug "Use default length $DEFAULT_ACCOUNT_KEY_LENGTH" - length="$DEFAULT_ACCOUNT_KEY_LENGTH" - fi - - _debug length "$length" - _initpath - - mkdir -p "$CA_DIR" - if [ -f "$ACCOUNT_KEY_PATH" ]; then - _info "Account key exists, skip" - return - else - #generate account key - _createkey "$length" "$ACCOUNT_KEY_PATH" - fi - -} - -#domain [length] -createDomainKey() { - _info "Creating domain key" - if [ -z "$1" ]; then - _usage "Usage: $PROJECT_ENTRY --createDomainKey -d domain.com [ --keylength 2048 ]" - return - fi - - domain=$1 - length=$2 - - if [ -z "$length" ]; then - _debug "Use DEFAULT_DOMAIN_KEY_LENGTH=$DEFAULT_DOMAIN_KEY_LENGTH" - length="$DEFAULT_DOMAIN_KEY_LENGTH" - fi - - _initpath "$domain" "$length" - - if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]); then - _createkey "$length" "$CERT_KEY_PATH" - else - if [ "$IS_RENEW" ]; then - _info "Domain key exists, skip" - return 0 - else - _err "Domain key exists, do you want to overwrite the key?" - _err "Add '--force', and try again." - return 1 - fi - fi - -} - -# domain domainlist isEcc -createCSR() { - _info "Creating csr" - if [ -z "$1" ]; then - _usage "Usage: $PROJECT_ENTRY --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ]" - return - fi - - domain="$1" - domainlist="$2" - _isEcc="$3" - - _initpath "$domain" "$_isEcc" - - if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && [ -z "$FORCE" ]; then - _info "CSR exists, skip" - return - fi - - if [ ! -f "$CERT_KEY_PATH" ]; then - _err "The key file is not found: $CERT_KEY_PATH" - _err "Please create the key file first." - return 1 - fi - _createcsr "$domain" "$domainlist" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF" - -} - -_url_replace() { - tr '/+' '_-' | tr -d '= ' -} - -_time2str() { - #Linux - if date -u -d@"$1" 2>/dev/null; then - return - fi - - #BSD - if date -u -r "$1" 2>/dev/null; then - return - fi - - #Soaris - if _exists adb; then - _t_s_a=$(echo "0t${1}=Y" | adb) - echo "$_t_s_a" - fi - -} - -_normalizeJson() { - sed "s/\" *: *\([\"{\[]\)/\":\1/g" | sed "s/^ *\([^ ]\)/\1/" | tr -d "\r\n" -} - -_stat() { - #Linux - if stat -c '%U:%G' "$1" 2>/dev/null; then - return - fi - - #BSD - if stat -f '%Su:%Sg' "$1" 2>/dev/null; then - return - fi - - return 1 #error, 'stat' not found -} - -#keyfile -_calcjwk() { - keyfile="$1" - if [ -z "$keyfile" ]; then - _usage "Usage: _calcjwk keyfile" - return 1 - fi - - if [ "$JWK_HEADER" ] && [ "$__CACHED_JWK_KEY_FILE" = "$keyfile" ]; then - _debug2 "Use cached jwk for file: $__CACHED_JWK_KEY_FILE" - return 0 - fi - - if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then - _debug "RSA key" - pub_exp=$($ACME_OPENSSL_BIN rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) - if [ "${#pub_exp}" = "5" ]; then - pub_exp=0$pub_exp - fi - _debug3 pub_exp "$pub_exp" - - e=$(echo "$pub_exp" | _h2b | _base64) - _debug3 e "$e" - - modulus=$($ACME_OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) - _debug3 modulus "$modulus" - n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)" - _debug3 n "$n" - - jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' - _debug3 jwk "$jwk" - - JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}' - JWK_HEADERPLACE_PART1='{"nonce": "' - JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}' - elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then - _debug "EC key" - crv="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" - _debug3 crv "$crv" - - if [ -z "$crv" ]; then - _debug "Let's try ASN1 OID" - crv_oid="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" - _debug3 crv_oid "$crv_oid" - case "${crv_oid}" in - "prime256v1") - crv="P-256" - ;; - "secp384r1") - crv="P-384" - ;; - "secp521r1") - crv="P-521" - ;; - *) - _err "ECC oid : $crv_oid" - return 1 - ;; - esac - _debug3 crv "$crv" - fi - - pubi="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" - pubi=$(_math "$pubi" + 1) - _debug3 pubi "$pubi" - - pubj="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" - pubj=$(_math "$pubj" - 1) - _debug3 pubj "$pubj" - - pubtext="$($ACME_OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" - _debug3 pubtext "$pubtext" - - xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" - xlen=$(_math "$xlen" / 4) - _debug3 xlen "$xlen" - - xend=$(_math "$xlen" + 1) - x="$(printf "%s" "$pubtext" | cut -d : -f 2-"$xend")" - _debug3 x "$x" - - x64="$(printf "%s" "$x" | tr -d : | _h2b | _base64 | _url_replace)" - _debug3 x64 "$x64" - - xend=$(_math "$xend" + 1) - y="$(printf "%s" "$pubtext" | cut -d : -f "$xend"-10000)" - _debug3 y "$y" - - y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _url_replace)" - _debug3 y64 "$y64" - - jwk='{"crv": "'$crv'", "kty": "EC", "x": "'$x64'", "y": "'$y64'"}' - _debug3 jwk "$jwk" - - JWK_HEADER='{"alg": "ES256", "jwk": '$jwk'}' - JWK_HEADERPLACE_PART1='{"nonce": "' - JWK_HEADERPLACE_PART2='", "alg": "ES256", "jwk": '$jwk'}' - else - _err "Only RSA or EC key is supported." - return 1 - fi - - _debug3 JWK_HEADER "$JWK_HEADER" - __CACHED_JWK_KEY_FILE="$keyfile" -} - -_time() { - date -u "+%s" -} - -_utc_date() { - date -u "+%Y-%m-%d %H:%M:%S" -} - -_mktemp() { - if _exists mktemp; then - if mktemp 2>/dev/null; then - return 0 - elif _contains "$(mktemp 2>&1)" "-t prefix" && mktemp -t "$PROJECT_NAME" 2>/dev/null; then - #for Mac osx - return 0 - fi - fi - if [ -d "/tmp" ]; then - echo "/tmp/${PROJECT_NAME}wefADf24sf.$(_time).tmp" - return 0 - elif [ "$LE_TEMP_DIR" ] && mkdir -p "$LE_TEMP_DIR"; then - echo "/$LE_TEMP_DIR/wefADf24sf.$(_time).tmp" - return 0 - fi - _err "Can not create temp file." -} - -_inithttp() { - - if [ -z "$HTTP_HEADER" ] || ! touch "$HTTP_HEADER"; then - HTTP_HEADER="$(_mktemp)" - _debug2 HTTP_HEADER "$HTTP_HEADER" - fi - - if [ "$__HTTP_INITIALIZED" ]; then - if [ "$_ACME_CURL$_ACME_WGET" ]; then - _debug2 "Http already initialized." - return 0 - fi - fi - - if [ -z "$_ACME_CURL" ] && _exists "curl"; then - _ACME_CURL="curl -L --silent --dump-header $HTTP_HEADER " - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - _CURL_DUMP="$(_mktemp)" - _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP " - fi - - if [ "$CA_BUNDLE" ]; then - _ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE " - fi - - fi - - if [ -z "$_ACME_WGET" ] && _exists "wget"; then - _ACME_WGET="wget -q" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - _ACME_WGET="$_ACME_WGET -d " - fi - if [ "$CA_BUNDLE" ]; then - _ACME_WGET="$_ACME_WGET --ca-certificate $CA_BUNDLE " - fi - fi - - #from wget 1.14: do not skip body on 404 error - if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help 2>&1)" "--content-on-error"; then - _ACME_WGET="$_ACME_WGET --content-on-error " - fi - - __HTTP_INITIALIZED=1 - -} - -# body url [needbase64] [POST|PUT] -_post() { - body="$1" - url="$2" - needbase64="$3" - httpmethod="$4" - - if [ -z "$httpmethod" ]; then - httpmethod="POST" - fi - _debug $httpmethod - _debug "url" "$url" - _debug2 "body" "$body" - - _inithttp - - if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then - _CURL="$_ACME_CURL" - if [ "$HTTPS_INSECURE" ]; then - _CURL="$_CURL --insecure " - fi - _debug "_CURL" "$_CURL" - if [ "$needbase64" ]; then - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" | _base64)" - else - response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url")" - fi - _ret="$?" - if [ "$_ret" != "0" ]; then - _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - _err "Here is the curl dump log:" - _err "$(cat "$_CURL_DUMP")" - fi - fi - elif [ "$_ACME_WGET" ]; then - _WGET="$_ACME_WGET" - if [ "$HTTPS_INSECURE" ]; then - _WGET="$_WGET --no-check-certificate " - fi - _debug "_WGET" "$_WGET" - if [ "$needbase64" ]; then - if [ "$httpmethod" = "POST" ]; then - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" - else - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)" - fi - else - if [ "$httpmethod" = "POST" ]; then - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")" - else - response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")" - fi - fi - _ret="$?" - if [ "$_ret" = "8" ]; then - _ret=0 - _debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later." - fi - if [ "$_ret" != "0" ]; then - _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" - fi - _sed_i "s/^ *//g" "$HTTP_HEADER" - else - _ret="$?" - _err "Neither curl nor wget is found, can not do $httpmethod." - fi - _debug "_ret" "$_ret" - printf "%s" "$response" - return $_ret -} - -# url getheader timeout -_get() { - _debug GET - url="$1" - onlyheader="$2" - t="$3" - _debug url "$url" - _debug "timeout" "$t" - - _inithttp - - if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then - _CURL="$_ACME_CURL" - if [ "$HTTPS_INSECURE" ]; then - _CURL="$_CURL --insecure " - fi - if [ "$t" ]; then - _CURL="$_CURL --connect-timeout $t" - fi - _debug "_CURL" "$_CURL" - if [ "$onlyheader" ]; then - $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" - else - $_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" - fi - ret=$? - if [ "$ret" != "0" ]; then - _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - _err "Here is the curl dump log:" - _err "$(cat "$_CURL_DUMP")" - fi - fi - elif [ "$_ACME_WGET" ]; then - _WGET="$_ACME_WGET" - if [ "$HTTPS_INSECURE" ]; then - _WGET="$_WGET --no-check-certificate " - fi - if [ "$t" ]; then - _WGET="$_WGET --timeout=$t" - fi - _debug "_WGET" "$_WGET" - if [ "$onlyheader" ]; then - $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null "$url" 2>&1 | sed 's/^[ ]*//g' - else - $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - "$url" - fi - ret=$? - if [ "$ret" = "8" ]; then - ret=0 - _debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later." - fi - if [ "$ret" != "0" ]; then - _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret" - fi - else - ret=$? - _err "Neither curl nor wget is found, can not do GET." - fi - _debug "ret" "$ret" - return $ret -} - -_head_n() { - head -n "$1" -} - -_tail_n() { - if ! tail -n "$1" 2>/dev/null; then - #fix for solaris - tail -"$1" - fi -} - -# url payload needbase64 keyfile -_send_signed_request() { - url=$1 - payload=$2 - needbase64=$3 - keyfile=$4 - if [ -z "$keyfile" ]; then - keyfile="$ACCOUNT_KEY_PATH" - fi - _debug url "$url" - _debug payload "$payload" - - if ! _calcjwk "$keyfile"; then - return 1 - fi - - payload64=$(printf "%s" "$payload" | _base64 | _url_replace) - _debug3 payload64 "$payload64" - - MAX_REQUEST_RETRY_TIMES=5 - _request_retry_times=0 - while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do - _debug3 _request_retry_times "$_request_retry_times" - if [ -z "$_CACHED_NONCE" ]; then - _debug2 "Get nonce." - nonceurl="$API/directory" - _headers="$(_get "$nonceurl" "onlyheader")" - - if [ "$?" != "0" ]; then - _err "Can not connect to $nonceurl to get nonce." - return 1 - fi - - _debug2 _headers "$_headers" - - _CACHED_NONCE="$(echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" - _debug2 _CACHED_NONCE "$_CACHED_NONCE" - else - _debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE" - fi - nonce="$_CACHED_NONCE" - _debug2 nonce "$nonce" - - protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2" - _debug3 protected "$protected" - - protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" - _debug3 protected64 "$protected64" - - if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then - _err "Sign request failed." - return 1 - fi - _debug3 _sig_t "$_sig_t" - - sig="$(printf "%s" "$_sig_t" | _url_replace)" - _debug3 sig "$sig" - - body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" - _debug3 body "$body" - - response="$(_post "$body" "$url" "$needbase64")" - _CACHED_NONCE="" - - if [ "$?" != "0" ]; then - _err "Can not post to $url" - return 1 - fi - _debug2 original "$response" - response="$(echo "$response" | _normalizeJson)" - - responseHeaders="$(cat "$HTTP_HEADER")" - - _debug2 responseHeaders "$responseHeaders" - _debug2 response "$response" - code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" - _debug code "$code" - - _CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" - - if _contains "$response" "JWS has invalid anti-replay nonce"; then - _info "It seems the CA server is busy now, let's wait and retry." - _request_retry_times=$(_math "$_request_retry_times" + 1) - _sleep 5 - continue - fi - break - done - -} - -#setopt "file" "opt" "=" "value" [";"] -_setopt() { - __conf="$1" - __opt="$2" - __sep="$3" - __val="$4" - __end="$5" - if [ -z "$__opt" ]; then - _usage usage: _setopt '"file" "opt" "=" "value" [";"]' - return - fi - if [ ! -f "$__conf" ]; then - touch "$__conf" - fi - - if grep -n "^$__opt$__sep" "$__conf" >/dev/null; then - _debug3 OK - if _contains "$__val" "&"; then - __val="$(echo "$__val" | sed 's/&/\\&/g')" - fi - text="$(cat "$__conf")" - printf -- "%s\n" "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" - - elif grep -n "^#$__opt$__sep" "$__conf" >/dev/null; then - if _contains "$__val" "&"; then - __val="$(echo "$__val" | sed 's/&/\\&/g')" - fi - text="$(cat "$__conf")" - printf -- "%s\n" "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" - - else - _debug3 APP - echo "$__opt$__sep$__val$__end" >>"$__conf" - fi - _debug3 "$(grep -n "^$__opt$__sep" "$__conf")" -} - -#_save_conf file key value -#save to conf -_save_conf() { - _s_c_f="$1" - _sdkey="$2" - _sdvalue="$3" - if [ "$_s_c_f" ]; then - _setopt "$_s_c_f" "$_sdkey" "=" "'$_sdvalue'" - else - _err "config file is empty, can not save $_sdkey=$_sdvalue" - fi -} - -#_clear_conf file key -_clear_conf() { - _c_c_f="$1" - _sdkey="$2" - if [ "$_c_c_f" ]; then - _conf_data="$(cat "$_c_c_f")" - echo "$_conf_data" | sed "s/^$_sdkey *=.*$//" >"$_c_c_f" - else - _err "config file is empty, can not clear" - fi -} - -#_read_conf file key -_read_conf() { - _r_c_f="$1" - _sdkey="$2" - if [ -f "$_r_c_f" ]; then - ( - eval "$(grep "^$_sdkey *=" "$_r_c_f")" - eval "printf \"%s\" \"\$$_sdkey\"" - ) - else - _debug "config file is empty, can not read $_sdkey" - fi -} - -#_savedomainconf key value -#save to domain.conf -_savedomainconf() { - _save_conf "$DOMAIN_CONF" "$1" "$2" -} - -#_cleardomainconf key -_cleardomainconf() { - _clear_conf "$DOMAIN_CONF" "$1" -} - -#_readdomainconf key -_readdomainconf() { - _read_conf "$DOMAIN_CONF" "$1" -} - -#_saveaccountconf key value -_saveaccountconf() { - _save_conf "$ACCOUNT_CONF_PATH" "$1" "$2" -} - -#_clearaccountconf key -_clearaccountconf() { - _clear_conf "$ACCOUNT_CONF_PATH" "$1" -} - -#_savecaconf key value -_savecaconf() { - _save_conf "$CA_CONF" "$1" "$2" -} - -#_readcaconf key -_readcaconf() { - _read_conf "$CA_CONF" "$1" -} - -#_clearaccountconf key -_clearcaconf() { - _clear_conf "$CA_CONF" "$1" -} - -# content localaddress -_startserver() { - content="$1" - ncaddr="$2" - _debug "ncaddr" "$ncaddr" - - _debug "startserver: $$" - nchelp="$(nc -h 2>&1)" - - _debug Le_HTTPPort "$Le_HTTPPort" - _debug Le_Listen_V4 "$Le_Listen_V4" - _debug Le_Listen_V6 "$Le_Listen_V6" - _NC="nc" - - if [ "$Le_Listen_V4" ]; then - _NC="$_NC -4" - elif [ "$Le_Listen_V6" ]; then - _NC="$_NC -6" - fi - - if [ "$Le_Listen_V4$Le_Listen_V6$ncaddr" ]; then - if ! _contains "$nchelp" "-4"; then - _err "The nc doesn't support '-4', '-6' or local-address, please install 'netcat-openbsd' and try again." - _err "See $(__green $_PREPARE_LINK)" - return 1 - fi - fi - - if echo "$nchelp" | grep "\-q[ ,]" >/dev/null; then - _NC="$_NC -q 1 -l $ncaddr" - else - if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null; then - _NC="$_NC -c -l $ncaddr" - elif echo "$nchelp" | grep "\-N" | grep "Shutdown the network socket after EOF on stdin" >/dev/null; then - _NC="$_NC -N -l $ncaddr" - else - _NC="$_NC -l $ncaddr" - fi - fi - - _debug "_NC" "$_NC" - - #for centos ncat - if _contains "$nchelp" "nmap.org"; then - _debug "Using ncat: nmap.org" - if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2"; then - _exec_err - return 1 - fi - if [ "$DEBUG" ]; then - _exec_err - fi - return - fi - - # while true ; do - if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC -p \"$Le_HTTPPort\" >&2"; then - _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2" - fi - - if [ "$?" != "0" ]; then - _err "nc listen error." - _exec_err - exit 1 - fi - if [ "$DEBUG" ]; then - _exec_err - fi - # done -} - -_stopserver() { - pid="$1" - _debug "pid" "$pid" - if [ -z "$pid" ]; then - return - fi - - _debug2 "Le_HTTPPort" "$Le_HTTPPort" - if [ "$Le_HTTPPort" ]; then - if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then - _get "http://localhost:$Le_HTTPPort" "" 1 - else - _get "http://localhost:$Le_HTTPPort" "" 1 >/dev/null 2>&1 - fi - fi - - _debug2 "Le_TLSPort" "$Le_TLSPort" - if [ "$Le_TLSPort" ]; then - if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then - _get "https://localhost:$Le_TLSPort" "" 1 - _get "https://localhost:$Le_TLSPort" "" 1 - else - _get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1 - _get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1 - fi - fi -} - -# sleep sec -_sleep() { - _sleep_sec="$1" - if [ "$__INTERACTIVE" ]; then - _sleep_c="$_sleep_sec" - while [ "$_sleep_c" -ge "0" ]; do - printf "\r \r" - __green "$_sleep_c" - _sleep_c="$(_math "$_sleep_c" - 1)" - sleep 1 - done - printf "\r" - else - sleep "$_sleep_sec" - fi -} - -# _starttlsserver san_a san_b port content _ncaddr -_starttlsserver() { - _info "Starting tls server." - san_a="$1" - san_b="$2" - port="$3" - content="$4" - opaddr="$5" - - _debug san_a "$san_a" - _debug san_b "$san_b" - _debug port "$port" - - #create key TLS_KEY - if ! _createkey "2048" "$TLS_KEY"; then - _err "Create tls validation key error." - return 1 - fi - - #create csr - alt="$san_a" - if [ "$san_b" ]; then - alt="$alt,$san_b" - fi - if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF"; then - _err "Create tls validation csr error." - return 1 - fi - - #self signed - if ! _signcsr "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$TLS_CERT"; then - _err "Create tls validation cert error." - return 1 - fi - - __S_OPENSSL="$ACME_OPENSSL_BIN s_server -cert $TLS_CERT -key $TLS_KEY " - if [ "$opaddr" ]; then - __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" - else - __S_OPENSSL="$__S_OPENSSL -accept $port" - fi - - _debug Le_Listen_V4 "$Le_Listen_V4" - _debug Le_Listen_V6 "$Le_Listen_V6" - if [ "$Le_Listen_V4" ]; then - __S_OPENSSL="$__S_OPENSSL -4" - elif [ "$Le_Listen_V6" ]; then - __S_OPENSSL="$__S_OPENSSL -6" - fi - - _debug "$__S_OPENSSL" - if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then - (printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL -tlsextdebug) & - else - (printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL >/dev/null 2>&1) & - fi - - serverproc="$!" - sleep 1 - _debug serverproc "$serverproc" -} - -#file -_readlink() { - _rf="$1" - if ! readlink -f "$_rf" 2>/dev/null; then - if _startswith "$_rf" "/"; then - echo "$_rf" - return 0 - fi - echo "$(pwd)/$_rf" | _conapath - fi -} - -_conapath() { - sed "s#/\./#/#g" -} - -__initHome() { - if [ -z "$_SCRIPT_HOME" ]; then - if _exists readlink && _exists dirname; then - _debug "Lets find script dir." - _debug "_SCRIPT_" "$_SCRIPT_" - _script="$(_readlink "$_SCRIPT_")" - _debug "_script" "$_script" - _script_home="$(dirname "$_script")" - _debug "_script_home" "$_script_home" - if [ -d "$_script_home" ]; then - _SCRIPT_HOME="$_script_home" - else - _err "It seems the script home is not correct:$_script_home" - fi - fi - fi - - # if [ -z "$LE_WORKING_DIR" ]; then - # if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then - # _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" - # LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" - # else - # LE_WORKING_DIR="$_SCRIPT_HOME" - # fi - # fi - - if [ -z "$LE_WORKING_DIR" ]; then - _debug "Using default home:$DEFAULT_INSTALL_HOME" - LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" - fi - export LE_WORKING_DIR - - if [ -z "$LE_CONFIG_HOME" ]; then - LE_CONFIG_HOME="$LE_WORKING_DIR" - fi - _debug "Using config home:$LE_CONFIG_HOME" - export LE_CONFIG_HOME - - _DEFAULT_ACCOUNT_CONF_PATH="$LE_CONFIG_HOME/account.conf" - - if [ -z "$ACCOUNT_CONF_PATH" ]; then - if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]; then - . "$_DEFAULT_ACCOUNT_CONF_PATH" - fi - fi - - if [ -z "$ACCOUNT_CONF_PATH" ]; then - ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH" - fi - - DEFAULT_LOG_FILE="$LE_CONFIG_HOME/$PROJECT_NAME.log" - - DEFAULT_CA_HOME="$LE_CONFIG_HOME/ca" - - if [ -z "$LE_TEMP_DIR" ]; then - LE_TEMP_DIR="$LE_CONFIG_HOME/tmp" - fi -} - -#[domain] [keylength] -_initpath() { - - __initHome - - if [ -f "$ACCOUNT_CONF_PATH" ]; then - . "$ACCOUNT_CONF_PATH" - fi - - if [ "$IN_CRON" ]; then - if [ ! "$_USER_PATH_EXPORTED" ]; then - _USER_PATH_EXPORTED=1 - export PATH="$USER_PATH:$PATH" - fi - fi - - if [ -z "$CA_HOME" ]; then - CA_HOME="$DEFAULT_CA_HOME" - fi - - if [ -z "$API" ]; then - if [ -z "$STAGE" ]; then - API="$DEFAULT_CA" - else - API="$STAGE_CA" - _info "Using stage api:$API" - fi - fi - - _API_HOST="$(echo "$API" | cut -d : -f 2 | tr -d '/')" - CA_DIR="$CA_HOME/$_API_HOST" - - _DEFAULT_CA_CONF="$CA_DIR/ca.conf" - - if [ -z "$CA_CONF" ]; then - CA_CONF="$_DEFAULT_CA_CONF" - fi - _debug3 CA_CONF "$CA_CONF" - - if [ -f "$CA_CONF" ]; then - . "$CA_CONF" - fi - - if [ -z "$ACME_DIR" ]; then - ACME_DIR="/home/.acme" - fi - - if [ -z "$APACHE_CONF_BACKUP_DIR" ]; then - APACHE_CONF_BACKUP_DIR="$LE_CONFIG_HOME" - fi - - if [ -z "$USER_AGENT" ]; then - USER_AGENT="$DEFAULT_USER_AGENT" - fi - - if [ -z "$HTTP_HEADER" ]; then - HTTP_HEADER="$LE_CONFIG_HOME/http.header" - fi - - _OLD_ACCOUNT_KEY="$LE_WORKING_DIR/account.key" - _OLD_ACCOUNT_JSON="$LE_WORKING_DIR/account.json" - - _DEFAULT_ACCOUNT_KEY_PATH="$CA_DIR/account.key" - _DEFAULT_ACCOUNT_JSON_PATH="$CA_DIR/account.json" - if [ -z "$ACCOUNT_KEY_PATH" ]; then - ACCOUNT_KEY_PATH="$_DEFAULT_ACCOUNT_KEY_PATH" - fi - - if [ -z "$ACCOUNT_JSON_PATH" ]; then - ACCOUNT_JSON_PATH="$_DEFAULT_ACCOUNT_JSON_PATH" - fi - - _DEFAULT_CERT_HOME="$LE_CONFIG_HOME" - if [ -z "$CERT_HOME" ]; then - CERT_HOME="$_DEFAULT_CERT_HOME" - fi - - if [ -z "$ACME_OPENSSL_BIN" ] || [ ! -f "$ACME_OPENSSL_BIN" ] || [ ! -x "$ACME_OPENSSL_BIN" ]; then - ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN" - fi - - if [ -z "$1" ]; then - return 0 - fi - - domain="$1" - _ilength="$2" - - if [ -z "$DOMAIN_PATH" ]; then - domainhome="$CERT_HOME/$domain" - domainhomeecc="$CERT_HOME/$domain$ECC_SUFFIX" - - DOMAIN_PATH="$domainhome" - - if _isEccKey "$_ilength"; then - DOMAIN_PATH="$domainhomeecc" - else - if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ]; then - _info "The domain '$domain' seems to have a ECC cert already, please add '$(__red "--ecc")' parameter if you want to use that cert." - fi - fi - _debug DOMAIN_PATH "$DOMAIN_PATH" - fi - - if [ -z "$DOMAIN_BACKUP_PATH" ]; then - DOMAIN_BACKUP_PATH="$DOMAIN_PATH/backup" - fi - - if [ -z "$DOMAIN_CONF" ]; then - DOMAIN_CONF="$DOMAIN_PATH/$domain.conf" - fi - - if [ -z "$DOMAIN_SSL_CONF" ]; then - DOMAIN_SSL_CONF="$DOMAIN_PATH/$domain.csr.conf" - fi - - if [ -z "$CSR_PATH" ]; then - CSR_PATH="$DOMAIN_PATH/$domain.csr" - fi - if [ -z "$CERT_KEY_PATH" ]; then - CERT_KEY_PATH="$DOMAIN_PATH/$domain.key" - fi - if [ -z "$CERT_PATH" ]; then - CERT_PATH="$DOMAIN_PATH/$domain.cer" - fi - if [ -z "$CA_CERT_PATH" ]; then - CA_CERT_PATH="$DOMAIN_PATH/ca.cer" - fi - if [ -z "$CERT_FULLCHAIN_PATH" ]; then - CERT_FULLCHAIN_PATH="$DOMAIN_PATH/fullchain.cer" - fi - if [ -z "$CERT_PFX_PATH" ]; then - CERT_PFX_PATH="$DOMAIN_PATH/$domain.pfx" - fi - if [ -z "$CERT_PKCS8_PATH" ]; then - CERT_PKCS8_PATH="$DOMAIN_PATH/$domain.pkcs8" - fi - - if [ -z "$TLS_CONF" ]; then - TLS_CONF="$DOMAIN_PATH/tls.valdation.conf" - fi - if [ -z "$TLS_CERT" ]; then - TLS_CERT="$DOMAIN_PATH/tls.valdation.cert" - fi - if [ -z "$TLS_KEY" ]; then - TLS_KEY="$DOMAIN_PATH/tls.valdation.key" - fi - if [ -z "$TLS_CSR" ]; then - TLS_CSR="$DOMAIN_PATH/tls.valdation.csr" - fi - -} - -_exec() { - if [ -z "$_EXEC_TEMP_ERR" ]; then - _EXEC_TEMP_ERR="$(_mktemp)" - fi - - if [ "$_EXEC_TEMP_ERR" ]; then - eval "$@ 2>>$_EXEC_TEMP_ERR" - else - eval "$@" - fi -} - -_exec_err() { - [ "$_EXEC_TEMP_ERR" ] && _err "$(cat "$_EXEC_TEMP_ERR")" && echo "" >"$_EXEC_TEMP_ERR" -} - -_apachePath() { - _APACHECTL="apachectl" - if ! _exists apachectl; then - if _exists apache2ctl; then - _APACHECTL="apache2ctl" - else - _err "'apachectl not found. It seems that apache is not installed, or you are not root user.'" - _err "Please use webroot mode to try again." - return 1 - fi - fi - - if ! _exec $_APACHECTL -V >/dev/null; then - _exec_err - return 1 - fi - - if [ "$APACHE_HTTPD_CONF" ]; then - _saveaccountconf APACHE_HTTPD_CONF "$APACHE_HTTPD_CONF" - httpdconf="$APACHE_HTTPD_CONF" - httpdconfname="$(basename "$httpdconfname")" - else - httpdconfname="$($_APACHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"')" - _debug httpdconfname "$httpdconfname" - - if [ -z "$httpdconfname" ]; then - _err "Can not read apache config file." - return 1 - fi - - if _startswith "$httpdconfname" '/'; then - httpdconf="$httpdconfname" - httpdconfname="$(basename "$httpdconfname")" - else - httpdroot="$($_APACHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"')" - _debug httpdroot "$httpdroot" - httpdconf="$httpdroot/$httpdconfname" - httpdconfname="$(basename "$httpdconfname")" - fi - fi - _debug httpdconf "$httpdconf" - _debug httpdconfname "$httpdconfname" - if [ ! -f "$httpdconf" ]; then - _err "Apache Config file not found" "$httpdconf" - return 1 - fi - return 0 -} - -_restoreApache() { - if [ -z "$usingApache" ]; then - return 0 - fi - _initpath - if ! _apachePath; then - return 1 - fi - - if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ]; then - _debug "No config file to restore." - return 0 - fi - - cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" >"$httpdconf" - _debug "Restored: $httpdconf." - if ! _exec $_APACHECTL -t; then - _exec_err - _err "Sorry, restore apache config error, please contact me." - return 1 - fi - _debug "Restored successfully." - rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" - return 0 -} - -_setApache() { - _initpath - if ! _apachePath; then - return 1 - fi - - #test the conf first - _info "Checking if there is an error in the apache config file before starting." - - if ! _exec "$_APACHECTL" -t >/dev/null; then - _exec_err - _err "The apache config file has error, please fix it first, then try again." - _err "Don't worry, there is nothing changed to your system." - return 1 - else - _info "OK" - fi - - #backup the conf - _debug "Backup apache config file" "$httpdconf" - if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/"; then - _err "Can not backup apache config file, so abort. Don't worry, the apache config is not changed." - _err "This might be a bug of $PROJECT_NAME , pleae report issue: $PROJECT" - return 1 - fi - _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" - _info "In case there is an error that can not be restored automatically, you may try restore it yourself." - _info "The backup file will be deleted on success, just forget it." - - #add alias - - apacheVer="$($_APACHECTL -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2)" - _debug "apacheVer" "$apacheVer" - apacheMajer="$(echo "$apacheVer" | cut -d . -f 1)" - apacheMinor="$(echo "$apacheVer" | cut -d . -f 2)" - - if [ "$apacheVer" ] && [ "$apacheMajer$apacheMinor" -ge "24" ]; then - echo " -Alias /.well-known/acme-challenge $ACME_DIR - - -Require all granted - - " >>"$httpdconf" - else - echo " -Alias /.well-known/acme-challenge $ACME_DIR - - -Order allow,deny -Allow from all - - " >>"$httpdconf" - fi - - _msg="$($_APACHECTL -t 2>&1)" - if [ "$?" != "0" ]; then - _err "Sorry, apache config error" - if _restoreApache; then - _err "The apache config file is restored." - else - _err "Sorry, The apache config file can not be restored, please report bug." - fi - return 1 - fi - - if [ ! -d "$ACME_DIR" ]; then - mkdir -p "$ACME_DIR" - chmod 755 "$ACME_DIR" - fi - - if ! _exec "$_APACHECTL" graceful; then - _exec_err - _err "$_APACHECTL graceful error, please contact me." - _restoreApache - return 1 - fi - usingApache="1" - return 0 -} - -#find the real nginx conf file -#backup -#set the nginx conf -#returns the real nginx conf file -_setNginx() { - _d="$1" - _croot="$2" - _thumbpt="$3" - if ! _exists "nginx"; then - _err "nginx command is not found." - return 1 - fi - FOUND_REAL_NGINX_CONF="" - FOUND_REAL_NGINX_CONF_LN="" - BACKUP_NGINX_CONF="" - _debug _croot "$_croot" - _start_f="$(echo "$_croot" | cut -d : -f 2)" - _debug _start_f "$_start_f" - if [ -z "$_start_f" ]; then - _debug "find start conf from nginx command" - if [ -z "$NGINX_CONF" ]; then - NGINX_CONF="$(nginx -V 2>&1 | _egrep_o "--conf-path=[^ ]* " | tr -d " ")" - _debug NGINX_CONF "$NGINX_CONF" - NGINX_CONF="$(echo "$NGINX_CONF" | cut -d = -f 2)" - _debug NGINX_CONF "$NGINX_CONF" - if [ ! -f "$NGINX_CONF" ]; then - _err "'$NGINX_CONF' doesn't exist." - NGINX_CONF="" - return 1 - fi - _debug "Found nginx conf file:$NGINX_CONF" - fi - _start_f="$NGINX_CONF" - fi - _debug "Start detect nginx conf for $_d from:$_start_f" - if ! _checkConf "$_d" "$_start_f"; then - _err "Can not find conf file for domain $d" - return 1 - fi - _info "Found conf file: $FOUND_REAL_NGINX_CONF" - - _ln=$FOUND_REAL_NGINX_CONF_LN - _debug "_ln" "$_ln" - - _lnn=$(_math $_ln + 1) - _debug _lnn "$_lnn" - _start_tag="$(sed -n "$_lnn,${_lnn}p" "$FOUND_REAL_NGINX_CONF")" - _debug "_start_tag" "$_start_tag" - if [ "$_start_tag" = "$NGINX_START" ]; then - _info "The domain $_d is already configured, skip" - FOUND_REAL_NGINX_CONF="" - return 0 - fi - - mkdir -p "$DOMAIN_BACKUP_PATH" - _backup_conf="$DOMAIN_BACKUP_PATH/$_d.nginx.conf" - _debug _backup_conf "$_backup_conf" - BACKUP_NGINX_CONF="$_backup_conf" - _info "Backup $FOUND_REAL_NGINX_CONF to $_backup_conf" - if ! cp "$FOUND_REAL_NGINX_CONF" "$_backup_conf"; then - _err "backup error." - FOUND_REAL_NGINX_CONF="" - return 1 - fi - - _info "Check the nginx conf before setting up." - if ! _exec "nginx -t" >/dev/null; then - _exec_err - return 1 - fi - - _info "OK, Set up nginx config file" - - if ! sed -n "1,${_ln}p" "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"; then - cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" - _err "write nginx conf error, but don't worry, the file is restored to the original version." - return 1 - fi - - echo "$NGINX_START -location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { - default_type text/plain; - return 200 \"\$1.$_thumbpt\"; -} -#NGINX_START -" >>"$FOUND_REAL_NGINX_CONF" - - if ! sed -n "${_lnn},99999p" "$_backup_conf" >>"$FOUND_REAL_NGINX_CONF"; then - cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" - _err "write nginx conf error, but don't worry, the file is restored." - return 1 - fi - - _info "nginx conf is done, let's check it again." - if ! _exec "nginx -t" >/dev/null; then - _exec_err - _err "It seems that nginx conf was broken, let's restore." - cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" - return 1 - fi - - _info "Reload nginx" - if ! _exec "nginx -s reload" >/dev/null; then - _exec_err - _err "It seems that nginx reload error, let's restore." - cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" - return 1 - fi - - return 0 -} - -#d , conf -_checkConf() { - _d="$1" - _c_file="$2" - _debug "Start _checkConf from:$_c_file" - 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 - return 0 - fi - done - #not found - return 1 - elif [ -f "$2" ]; then - _debug "single" - if _isRealNginxConf "$1" "$2"; then - _debug "$2 is found." - FOUND_REAL_NGINX_CONF="$2" - return 0 - fi - if cat "$2" | tr "\t" " " | grep "^ *include *.*;" >/dev/null; then - _debug "Try include files" - for included in $(cat "$2" | tr "\t" " " | grep "^ *include *.*;" | sed "s/include //" | tr -d " ;"); do - _debug "check included $included" - if _checkConf "$1" "$included"; then - return 0 - fi - done - fi - return 1 - else - _debug "$2 not found." - return 1 - fi - return 1 -} - -#d , conf -_isRealNginxConf() { - _debug "_isRealNginxConf $1 $2" - if [ -f "$2" ]; then - for _fln in $(grep -n "^ *server_name.* $1" "$2" | cut -d : -f 1); do - _debug _fln "$_fln" - if [ "$_fln" ]; then - _start=$(cat "$2" | _head_n "$_fln" | grep -n "^ *server *{" | _tail_n 1) - _debug "_start" "$_start" - _start_n=$(echo "$_start" | cut -d : -f 1) - _start_nn=$(_math $_start_n + 1) - _debug "_start_n" "$_start_n" - _debug "_start_nn" "$_start_nn" - - _left="$(sed -n "${_start_nn},99999p" "$2")" - _debug2 _left "$_left" - if echo "$_left" | grep -n "^ *server *{" >/dev/null; then - _end=$(echo "$_left" | grep -n "^ *server *{" | _head_n 1) - _debug "_end" "$_end" - _end_n=$(echo "$_end" | cut -d : -f 1) - _debug "_end_n" "$_end_n" - _seg_n=$(echo "$_left" | sed -n "1,${_end_n}p") - else - _seg_n="$_left" - fi - - _debug "_seg_n" "$_seg_n" - - if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ]; then - _debug "ssl on, skip" - return 1 - fi - FOUND_REAL_NGINX_CONF_LN=$_fln - return 0 - fi - done - fi - return 1 -} - -#restore all the nginx conf -_restoreNginx() { - if [ -z "$NGINX_RESTORE_VLIST" ]; then - _debug "No need to restore nginx, skip." - return - fi - _debug "_restoreNginx" - _debug "NGINX_RESTORE_VLIST" "$NGINX_RESTORE_VLIST" - - for ng_entry in $(echo "$NGINX_RESTORE_VLIST" | tr "$dvsep" ' '); do - _debug "ng_entry" "$ng_entry" - _nd=$(echo "$ng_entry" | cut -d "$sep" -f 1) - _ngconf=$(echo "$ng_entry" | cut -d "$sep" -f 2) - _ngbackupconf=$(echo "$ng_entry" | cut -d "$sep" -f 3) - _info "Restoring from $_ngbackupconf to $_ngconf" - cat "$_ngbackupconf" >"$_ngconf" - done - - _info "Reload nginx" - if ! _exec "nginx -s reload" >/dev/null; then - _exec_err - _err "It seems that nginx reload error, please report bug." - return 1 - fi - return 0 -} - -_clearup() { - _stopserver "$serverproc" - serverproc="" - _restoreApache - _restoreNginx - _clearupdns - if [ -z "$DEBUG" ]; then - rm -f "$TLS_CONF" - rm -f "$TLS_CERT" - rm -f "$TLS_KEY" - rm -f "$TLS_CSR" - fi -} - -_clearupdns() { - _debug "_clearupdns" - if [ "$dnsadded" != 1 ] || [ -z "$vlist" ]; then - _debug "Dns not added, skip." - return - fi - - ventries=$(echo "$vlist" | tr ',' ' ') - for ventry in $ventries; do - d=$(echo "$ventry" | cut -d "$sep" -f 1) - keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) - vtype=$(echo "$ventry" | cut -d "$sep" -f 4) - _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) - txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" - _debug txt "$txt" - if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then - _debug "$d is already verified, skip $vtype." - continue - fi - - if [ "$vtype" != "$VTYPE_DNS" ]; then - _info "Skip $d for $vtype" - continue - fi - - d_api="$(_findHook "$d" dnsapi "$_currentRoot")" - _debug d_api "$d_api" - - if [ -z "$d_api" ]; then - _info "Not Found domain api file: $d_api" - continue - fi - - ( - if ! . "$d_api"; then - _err "Load file $d_api error. Please check your api file and try again." - return 1 - fi - - rmcommand="${_currentRoot}_rm" - if ! _exists "$rmcommand"; then - _err "It seems that your api file doesn't define $rmcommand" - return 1 - fi - - txtdomain="_acme-challenge.$d" - - if ! $rmcommand "$txtdomain" "$txt"; then - _err "Error removing txt for domain:$txtdomain" - return 1 - fi - ) - - done -} - -# webroot removelevel tokenfile -_clearupwebbroot() { - __webroot="$1" - if [ -z "$__webroot" ]; then - _debug "no webroot specified, skip" - return 0 - fi - - _rmpath="" - if [ "$2" = '1' ]; then - _rmpath="$__webroot/.well-known" - elif [ "$2" = '2' ]; then - _rmpath="$__webroot/.well-known/acme-challenge" - elif [ "$2" = '3' ]; then - _rmpath="$__webroot/.well-known/acme-challenge/$3" - else - _debug "Skip for removelevel:$2" - fi - - if [ "$_rmpath" ]; then - if [ "$DEBUG" ]; then - _debug "Debugging, skip removing: $_rmpath" - else - rm -rf "$_rmpath" - fi - fi - - return 0 - -} - -_on_before_issue() { - _chk_web_roots="$1" - _chk_main_domain="$2" - _chk_alt_domains="$3" - _chk_pre_hook="$4" - _chk_local_addr="$5" - _debug _on_before_issue - #run pre hook - if [ "$_chk_pre_hook" ]; then - _info "Run pre hook:'$_chk_pre_hook'" - if ! ( - cd "$DOMAIN_PATH" && eval "$_chk_pre_hook" - ); then - _err "Error when run pre hook." - return 1 - fi - fi - - if _hasfield "$_chk_web_roots" "$NO_VALUE"; then - if ! _exists "nc"; then - _err "Please install netcat(nc) tools first." - return 1 - fi - fi - - _debug Le_LocalAddress "$_chk_local_addr" - - alldomains=$(echo "$_chk_main_domain,$_chk_alt_domains" | tr ',' ' ') - _index=1 - _currentRoot="" - _addrIndex=1 - for d in $alldomains; do - _debug "Check for domain" "$d" - _currentRoot="$(_getfield "$_chk_web_roots" $_index)" - _debug "_currentRoot" "$_currentRoot" - _index=$(_math $_index + 1) - _checkport="" - if [ "$_currentRoot" = "$NO_VALUE" ]; then - _info "Standalone mode." - if [ -z "$Le_HTTPPort" ]; then - Le_HTTPPort=80 - else - _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" - fi - _checkport="$Le_HTTPPort" - elif [ "$_currentRoot" = "$W_TLS" ]; then - _info "Standalone tls mode." - if [ -z "$Le_TLSPort" ]; then - Le_TLSPort=443 - else - _savedomainconf "Le_TLSPort" "$Le_TLSPort" - fi - _checkport="$Le_TLSPort" - fi - - if [ "$_checkport" ]; then - _debug _checkport "$_checkport" - _checkaddr="$(_getfield "$_chk_local_addr" $_addrIndex)" - _debug _checkaddr "$_checkaddr" - - _addrIndex="$(_math $_addrIndex + 1)" - - _netprc="$(_ss "$_checkport" | grep "$_checkport")" - netprc="$(echo "$_netprc" | grep "$_checkaddr")" - if [ -z "$netprc" ]; then - netprc="$(echo "$_netprc" | grep "$LOCAL_ANY_ADDRESS")" - fi - if [ "$netprc" ]; then - _err "$netprc" - _err "tcp port $_checkport is already used by $(echo "$netprc" | cut -d : -f 4)" - _err "Please stop it first" - return 1 - fi - fi - done - - if _hasfield "$_chk_web_roots" "apache"; then - if ! _setApache; then - _err "set up apache error. Report error to me." - return 1 - fi - else - usingApache="" - fi - -} - -_on_issue_err() { - _chk_post_hook="$1" - _chk_vlist="$2" - _debug _on_issue_err - if [ "$LOG_FILE" ]; then - _err "Please check log file for more details: $LOG_FILE" - else - _err "Please add '--debug' or '--log' to check more details." - _err "See: $_DEBUG_WIKI" - fi - - #run the post hook - if [ "$_chk_post_hook" ]; then - _info "Run post hook:'$_chk_post_hook'" - if ! ( - cd "$DOMAIN_PATH" && eval "$_chk_post_hook" - ); then - _err "Error when run post hook." - return 1 - fi - fi - - #trigger the validation to flush the pending authz - if [ "$_chk_vlist" ]; then - ( - _debug2 "_chk_vlist" "$_chk_vlist" - _debug2 "start to deactivate authz" - ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ') - for ventry in $ventries; do - d=$(echo "$ventry" | cut -d "$sep" -f 1) - keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) - uri=$(echo "$ventry" | cut -d "$sep" -f 3) - vtype=$(echo "$ventry" | cut -d "$sep" -f 4) - _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) - __trigger_validaton "$uri" "$keyauthorization" - done - ) - fi - - if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then - _debug "$(_dlg_versions)" - fi - -} - -_on_issue_success() { - _chk_post_hook="$1" - _chk_renew_hook="$2" - _debug _on_issue_success - #run the post hook - if [ "$_chk_post_hook" ]; then - _info "Run post hook:'$_chk_post_hook'" - if ! ( - cd "$DOMAIN_PATH" && eval "$_chk_post_hook" - ); then - _err "Error when run post hook." - return 1 - fi - fi - - #run renew hook - if [ "$IS_RENEW" ] && [ "$_chk_renew_hook" ]; then - _info "Run renew hook:'$_chk_renew_hook'" - if ! ( - cd "$DOMAIN_PATH" && eval "$_chk_renew_hook" - ); then - _err "Error when run renew hook." - return 1 - fi - fi - -} - -updateaccount() { - _initpath - _regAccount -} - -registeraccount() { - _reg_length="$1" - _initpath - _regAccount "$_reg_length" -} - -__calcAccountKeyHash() { - [ -f "$ACCOUNT_KEY_PATH" ] && _digest sha256 <"$ACCOUNT_KEY_PATH" -} - -__calc_account_thumbprint() { - printf "%s" "$jwk" | tr -d ' ' | _digest "sha256" | _url_replace -} - -#keylength -_regAccount() { - _initpath - _reg_length="$1" - - if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then - mkdir -p "$CA_DIR" - _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" - mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH" - fi - - if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then - mkdir -p "$CA_DIR" - _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" - mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" - fi - - if [ ! -f "$ACCOUNT_KEY_PATH" ]; then - if ! _create_account_key "$_reg_length"; then - _err "Create account key error." - return 1 - fi - fi - - if ! _calcjwk "$ACCOUNT_KEY_PATH"; then - return 1 - fi - - _updateTos="" - _reg_res="new-reg" - while true; do - _debug AGREEMENT "$AGREEMENT" - - regjson='{"resource": "'$_reg_res'", "agreement": "'$AGREEMENT'"}' - - if [ "$ACCOUNT_EMAIL" ]; then - regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' - fi - - if [ -z "$_updateTos" ]; then - _info "Registering account" - - if ! _send_signed_request "$API/acme/new-reg" "$regjson"; then - _err "Register account Error: $response" - return 1 - fi - - if [ "$code" = "" ] || [ "$code" = '201' ]; then - echo "$response" >"$ACCOUNT_JSON_PATH" - _info "Registered" - elif [ "$code" = '409' ]; then - _info "Already registered" - else - _err "Register account Error: $response" - return 1 - fi - - _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" - _debug "_accUri" "$_accUri" - - _tos="$(echo "$responseHeaders" | grep "^Link:.*rel=\"terms-of-service\"" | _head_n 1 | _egrep_o "<.*>" | tr -d '<>')" - _debug "_tos" "$_tos" - if [ -z "$_tos" ]; then - _debug "Use default tos: $DEFAULT_AGREEMENT" - _tos="$DEFAULT_AGREEMENT" - fi - if [ "$_tos" != "$AGREEMENT" ]; then - _updateTos=1 - AGREEMENT="$_tos" - _reg_res="reg" - continue - fi - - else - _debug "Update tos: $_tos" - if ! _send_signed_request "$_accUri" "$regjson"; then - _err "Update tos error." - return 1 - fi - if [ "$code" = '202' ]; then - _info "Update success." - - CA_KEY_HASH="$(__calcAccountKeyHash)" - _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" - _savecaconf CA_KEY_HASH "$CA_KEY_HASH" - else - _err "Update account error." - return 1 - fi - fi - ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)" - _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT" - return 0 - done - -} - -# domain folder file -_findHook() { - _hookdomain="$1" - _hookcat="$2" - _hookname="$3" - - if [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname" ]; then - 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 - d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname" - elif [ -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" - elif [ -f "$LE_WORKING_DIR/$_hookname.sh" ]; then - d_api="$LE_WORKING_DIR/$_hookname.sh" - elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname" ]; then - d_api="$LE_WORKING_DIR/$_hookcat/$_hookname" - elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname.sh" ]; then - d_api="$LE_WORKING_DIR/$_hookcat/$_hookname.sh" - fi - - printf "%s" "$d_api" -} - -#domain -__get_domain_new_authz() { - _gdnd="$1" - _info "Getting new-authz for domain" "$_gdnd" - - _Max_new_authz_retry_times=5 - _authz_i=0 - while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do - _debug "Try new-authz for the $_authz_i time." - if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then - _err "Can not get domain new authz." - return 1 - fi - if _contains "$response" "No registration exists matching provided key"; then - _err "It seems there is an error, but it's recovered now, please try again." - _err "If you see this message for a second time, please report bug: $(__green "$PROJECT")" - _clearcaconf "CA_KEY_HASH" - break - fi - if ! _contains "$response" "An error occurred while processing your request"; then - _info "The new-authz request is ok." - break - fi - _authz_i="$(_math "$_authz_i" + 1)" - _info "The server is busy, Sleep $_authz_i to retry." - _sleep "$_authz_i" - done - - if [ "$_authz_i" = "$_Max_new_authz_retry_times" ]; then - _err "new-authz retry reach the max $_Max_new_authz_retry_times times." - fi - - if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then - _err "new-authz error: $response" - return 1 - fi - -} - -#uri keyAuthorization -__trigger_validaton() { - _debug2 "tigger domain validation." - _t_url="$1" - _debug2 _t_url "$_t_url" - _t_key_authz="$2" - _debug2 _t_key_authz "$_t_key_authz" - _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}" -} - -#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 - _web_roots="$1" - _main_domain="$2" - _alt_domains="$3" - if _contains "$_main_domain" ","; then - _main_domain=$(echo "$2,$3" | cut -d , -f 1) - _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") - fi - _key_length="$4" - _real_cert="$5" - _real_key="$6" - _real_ca="$7" - _reload_cmd="$8" - _real_fullchain="$9" - _pre_hook="${10}" - _post_hook="${11}" - _renew_hook="${12}" - _local_addr="${13}" - - #remove these later. - if [ "$_web_roots" = "dns-cf" ]; then - _web_roots="dns_cf" - fi - if [ "$_web_roots" = "dns-dp" ]; then - _web_roots="dns_dp" - fi - if [ "$_web_roots" = "dns-cx" ]; then - _web_roots="dns_cx" - fi - _debug "Using api: $API" - - if [ ! "$IS_RENEW" ]; then - _initpath "$_main_domain" "$_key_length" - mkdir -p "$DOMAIN_PATH" - fi - - if [ -f "$DOMAIN_CONF" ]; then - Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) - _debug Le_NextRenewTime "$Le_NextRenewTime" - if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then - _saved_domain=$(_readdomainconf Le_Domain) - _debug _saved_domain "$_saved_domain" - _saved_alt=$(_readdomainconf Le_Alt) - _debug _saved_alt "$_saved_alt" - if [ "$_saved_domain,$_saved_alt" = "$_main_domain,$_alt_domains" ]; then - _info "Domains not changed." - _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")" - _info "Add '$(__red '--force')' to force to renew." - return $RENEW_SKIP - else - _info "Domains have changed." - fi - fi - fi - - _savedomainconf "Le_Domain" "$_main_domain" - _savedomainconf "Le_Alt" "$_alt_domains" - _savedomainconf "Le_Webroot" "$_web_roots" - - _savedomainconf "Le_PreHook" "$_pre_hook" - _savedomainconf "Le_PostHook" "$_post_hook" - _savedomainconf "Le_RenewHook" "$_renew_hook" - - if [ "$_local_addr" ]; then - _savedomainconf "Le_LocalAddress" "$_local_addr" - else - _cleardomainconf "Le_LocalAddress" - fi - - Le_API="$API" - _savedomainconf "Le_API" "$Le_API" - - if [ "$_alt_domains" = "$NO_VALUE" ]; then - _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 - fi - - _saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")" - _debug2 _saved_account_key_hash "$_saved_account_key_hash" - - if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then - if ! _regAccount "$_accountkeylength"; then - _on_issue_err "$_post_hook" - return 1 - fi - else - _debug "_saved_account_key_hash is not changed, skip register account." - fi - - if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ]; then - _info "Signing from existing CSR." - else - _key=$(_readdomainconf Le_Keylength) - _debug "Read key length:$_key" - if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ]; then - if ! createDomainKey "$_main_domain" "$_key_length"; then - _err "Create domain key error." - _clearup - _on_issue_err "$_post_hook" - return 1 - fi - fi - - if ! _createcsr "$_main_domain" "$_alt_domains" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then - _err "Create CSR error." - _clearup - _on_issue_err "$_post_hook" - return 1 - fi - fi - - _savedomainconf "Le_Keylength" "$_key_length" - - vlist="$Le_Vlist" - - _info "Getting domain auth token for each domain" - sep='#' - dvsep=',' - if [ -z "$vlist" ]; then - alldomains=$(echo "$_main_domain,$_alt_domains" | tr ',' ' ') - _index=1 - _currentRoot="" - for d in $alldomains; do - _info "Getting webroot for domain" "$d" - _w="$(echo $_web_roots | cut -d , -f $_index)" - _debug _w "$_w" - if [ "$_w" ]; then - _currentRoot="$_w" - fi - _debug "_currentRoot" "$_currentRoot" - _index=$(_math $_index + 1) - - vtype="$VTYPE_HTTP" - if _startswith "$_currentRoot" "dns"; then - vtype="$VTYPE_DNS" - fi - - if [ "$_currentRoot" = "$W_TLS" ]; then - vtype="$VTYPE_TLS" - fi - - if ! __get_domain_new_authz "$d"; then - _clearup - _on_issue_err "$_post_hook" - return 1 - fi - - if [ -z "$thumbprint" ]; then - thumbprint="$(__calc_account_thumbprint)" - fi - - entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" - _debug entry "$entry" - if [ -z "$entry" ]; then - _err "Error, can not get domain token $d" - _clearup - _on_issue_err "$_post_hook" - return 1 - fi - token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" - _debug token "$token" - - uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" - _debug uri "$uri" - - keyauthorization="$token.$thumbprint" - _debug keyauthorization "$keyauthorization" - - if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then - _debug "$d is already verified, skip." - keyauthorization="$STATE_VERIFIED" - _debug keyauthorization "$keyauthorization" - fi - - dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot" - _debug dvlist "$dvlist" - - vlist="$vlist$dvlist$dvsep" - - done - _debug vlist "$vlist" - #add entry - dnsadded="" - ventries=$(echo "$vlist" | tr "$dvsep" ' ') - for ventry in $ventries; do - d=$(echo "$ventry" | cut -d "$sep" -f 1) - keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) - vtype=$(echo "$ventry" | cut -d "$sep" -f 4) - _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) - - if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then - _debug "$d is already verified, skip $vtype." - continue - fi - - if [ "$vtype" = "$VTYPE_DNS" ]; then - dnsadded='0' - txtdomain="_acme-challenge.$d" - _debug txtdomain "$txtdomain" - txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" - _debug txt "$txt" - - d_api="$(_findHook "$d" dnsapi "$_currentRoot")" - - _debug d_api "$d_api" - - if [ "$d_api" ]; then - _info "Found domain api file: $d_api" - else - _err "Add the following TXT record:" - _err "Domain: '$(__green "$txtdomain")'" - _err "TXT value: '$(__green "$txt")'" - _err "Please be aware that you prepend _acme-challenge. before your domain" - _err "so the resulting subdomain will be: $txtdomain" - continue - fi - - ( - if ! . "$d_api"; then - _err "Load file $d_api error. Please check your api file and try again." - return 1 - fi - - addcommand="${_currentRoot}_add" - if ! _exists "$addcommand"; then - _err "It seems that your api file is not correct, it must have a function named: $addcommand" - return 1 - fi - - if ! $addcommand "$txtdomain" "$txt"; then - _err "Error add txt for domain:$txtdomain" - return 1 - fi - ) - - if [ "$?" != "0" ]; then - _clearup - _on_issue_err "$_post_hook" - return 1 - fi - dnsadded='1' - fi - done - - if [ "$dnsadded" = '0' ]; then - _savedomainconf "Le_Vlist" "$vlist" - _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." - _clearup - _on_issue_err "$_post_hook" - return 1 - fi - - fi - - if [ "$dnsadded" = '1' ]; then - if [ -z "$Le_DNSSleep" ]; then - Le_DNSSleep="$DEFAULT_DNS_SLEEP" - else - _savedomainconf "Le_DNSSleep" "$Le_DNSSleep" - fi - - _info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect" - _sleep "$Le_DNSSleep" - fi - - NGINX_RESTORE_VLIST="" - _debug "ok, let's start to verify" - - _ncIndex=1 - ventries=$(echo "$vlist" | tr "$dvsep" ' ') - for ventry in $ventries; do - d=$(echo "$ventry" | cut -d "$sep" -f 1) - keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) - uri=$(echo "$ventry" | cut -d "$sep" -f 3) - vtype=$(echo "$ventry" | cut -d "$sep" -f 4) - _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) - - if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then - _info "$d is already verified, skip $vtype." - continue - fi - - _info "Verifying:$d" - _debug "d" "$d" - _debug "keyauthorization" "$keyauthorization" - _debug "uri" "$uri" - removelevel="" - token="$(printf "%s" "$keyauthorization" | cut -d '.' -f 1)" - - _debug "_currentRoot" "$_currentRoot" - - if [ "$vtype" = "$VTYPE_HTTP" ]; then - if [ "$_currentRoot" = "$NO_VALUE" ]; then - _info "Standalone mode server" - _ncaddr="$(_getfield "$_local_addr" "$_ncIndex")" - _ncIndex="$(_math $_ncIndex + 1)" - _startserver "$keyauthorization" "$_ncaddr" & - if [ "$?" != "0" ]; then - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 - fi - serverproc="$!" - sleep 1 - _debug serverproc "$serverproc" - elif [ "$_currentRoot" = "$MODE_STATELESS" ]; then - _info "Stateless mode for domain:$d" - _sleep 1 - elif _startswith "$_currentRoot" "$NGINX"; then - _info "Nginx mode for domain:$d" - #set up nginx server - FOUND_REAL_NGINX_CONF="" - BACKUP_NGINX_CONF="" - if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 - fi - - if [ "$FOUND_REAL_NGINX_CONF" ]; then - _realConf="$FOUND_REAL_NGINX_CONF" - _backup="$BACKUP_NGINX_CONF" - _debug _realConf "$_realConf" - NGINX_RESTORE_VLIST="$d$sep$_realConf$sep$_backup$dvsep$NGINX_RESTORE_VLIST" - fi - _sleep 1 - else - if [ "$_currentRoot" = "apache" ]; then - wellknown_path="$ACME_DIR" - else - wellknown_path="$_currentRoot/.well-known/acme-challenge" - if [ ! -d "$_currentRoot/.well-known" ]; then - removelevel='1' - elif [ ! -d "$_currentRoot/.well-known/acme-challenge" ]; then - removelevel='2' - else - removelevel='3' - fi - fi - - _debug wellknown_path "$wellknown_path" - - _debug "writing token:$token to $wellknown_path/$token" - - mkdir -p "$wellknown_path" - - if ! printf "%s" "$keyauthorization" >"$wellknown_path/$token"; then - _err "$d:Can not write token to file : $wellknown_path/$token" - _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 - fi - - if [ ! "$usingApache" ]; then - if webroot_owner=$(_stat "$_currentRoot"); then - _debug "Changing owner/group of .well-known to $webroot_owner" - chown -R "$webroot_owner" "$_currentRoot/.well-known" - else - _debug "not chaning owner/group of webroot" - fi - fi - - fi - - elif [ "$vtype" = "$VTYPE_TLS" ]; then - #create A - #_hash_A="$(printf "%s" $token | _digest "sha256" "hex" )" - #_debug2 _hash_A "$_hash_A" - #_x="$(echo $_hash_A | cut -c 1-32)" - #_debug2 _x "$_x" - #_y="$(echo $_hash_A | cut -c 33-64)" - #_debug2 _y "$_y" - #_SAN_A="$_x.$_y.token.acme.invalid" - #_debug2 _SAN_A "$_SAN_A" - - #create B - _hash_B="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")" - _debug2 _hash_B "$_hash_B" - _x="$(echo "$_hash_B" | cut -c 1-32)" - _debug2 _x "$_x" - _y="$(echo "$_hash_B" | cut -c 33-64)" - _debug2 _y "$_y" - - #_SAN_B="$_x.$_y.ka.acme.invalid" - - _SAN_B="$_x.$_y.acme.invalid" - _debug2 _SAN_B "$_SAN_B" - - _ncaddr="$(_getfield "$_local_addr" "$_ncIndex")" - _ncIndex="$(_math "$_ncIndex" + 1)" - if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" "$_ncaddr"; then - _err "Start tls server error." - _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 - fi - fi - - if ! __trigger_validaton "$uri" "$keyauthorization"; then - _err "$d:Can not get challenge: $response" - _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 - fi - - if [ ! -z "$code" ] && [ ! "$code" = '202' ]; then - _err "$d:Challenge error: $response" - _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 - fi - - waittimes=0 - if [ -z "$MAX_RETRY_TIMES" ]; then - MAX_RETRY_TIMES=30 - fi - - while true; do - waittimes=$(_math "$waittimes" + 1) - if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ]; then - _err "$d:Timeout" - _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 - fi - - _debug "sleep 2 secs to verify" - sleep 2 - _debug "checking" - response="$(_get "$uri")" - if [ "$?" != "0" ]; then - _err "$d:Verify error:$response" - _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 - fi - _debug2 original "$response" - - response="$(echo "$response" | _normalizeJson)" - _debug2 response "$response" - - status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"') - if [ "$status" = "valid" ]; then - _info "$(__green Success)" - _stopserver "$serverproc" - serverproc="" - _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - break - fi - - if [ "$status" = "invalid" ]; then - error="$(echo "$response" | tr -d "\r\n" | _egrep_o '"error":\{[^\}]*')" - _debug2 error "$error" - errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)" - _debug2 errordetail "$errordetail" - if [ "$errordetail" ]; then - _err "$d:Verify error:$errordetail" - else - _err "$d:Verify error:$error" - fi - if [ "$DEBUG" ]; then - if [ "$vtype" = "$VTYPE_HTTP" ]; then - _debug "Debug: get token url." - _get "http://$d/.well-known/acme-challenge/$token" "" 1 - fi - fi - _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 - fi - - if [ "$status" = "pending" ]; then - _info "Pending" - else - _err "$d:Verify error:$response" - _clearupwebbroot "$_currentRoot" "$removelevel" "$token" - _clearup - _on_issue_err "$_post_hook" "$vlist" - return 1 - fi - - done - - done - - _clearup - _info "Verify finished, start to sign." - der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" - - if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then - _err "Sign failed." - _on_issue_err "$_post_hook" - return 1 - fi - - _rcert="$response" - Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" - _savedomainconf "Le_LinkCert" "$Le_LinkCert" - - if [ "$Le_LinkCert" ]; then - echo "$BEGIN_CERT" >"$CERT_PATH" - - #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" - #fi - - if ! printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >>"$CERT_PATH"; then - _debug "Try cert link." - _get "$Le_LinkCert" | _base64 "multiline" >>"$CERT_PATH" - fi - - echo "$END_CERT" >>"$CERT_PATH" - _info "$(__green "Cert success.")" - cat "$CERT_PATH" - - _info "Your cert is in $(__green " $CERT_PATH ")" - - if [ -f "$CERT_KEY_PATH" ]; then - _info "Your cert key is in $(__green " $CERT_KEY_PATH ")" - fi - - cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH" - - if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ]; then - USER_PATH="$PATH" - _saveaccountconf "USER_PATH" "$USER_PATH" - fi - fi - - if [ -z "$Le_LinkCert" ]; then - response="$(echo "$response" | _dbase64 "multiline" | _normalizeJson)" - _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')" - _on_issue_err "$_post_hook" - return 1 - fi - - _cleardomainconf "Le_Vlist" - - Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') - if ! _contains "$Le_LinkIssuer" ":"; then - Le_LinkIssuer="$API$Le_LinkIssuer" - fi - - _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" - - if [ "$Le_LinkIssuer" ]; then - echo "$BEGIN_CERT" >"$CA_CERT_PATH" - _get "$Le_LinkIssuer" | _base64 "multiline" >>"$CA_CERT_PATH" - echo "$END_CERT" >>"$CA_CERT_PATH" - _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")" - cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH" - _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")" - fi - - Le_CertCreateTime=$(_time) - _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime" - - Le_CertCreateTimeStr=$(date -u) - _savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr" - - if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "$MAX_RENEW" ]; then - Le_RenewalDays="$MAX_RENEW" - else - _savedomainconf "Le_RenewalDays" "$Le_RenewalDays" - fi - - if [ "$CA_BUNDLE" ]; then - _saveaccountconf CA_BUNDLE "$CA_BUNDLE" - else - _clearaccountconf "CA_BUNDLE" - fi - - if [ "$HTTPS_INSECURE" ]; then - _saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE" - else - _clearaccountconf "HTTPS_INSECURE" - fi - - if [ "$Le_Listen_V4" ]; then - _savedomainconf "Le_Listen_V4" "$Le_Listen_V4" - _cleardomainconf Le_Listen_V6 - elif [ "$Le_Listen_V6" ]; then - _savedomainconf "Le_Listen_V6" "$Le_Listen_V6" - _cleardomainconf Le_Listen_V4 - fi - - Le_NextRenewTime=$(_math "$Le_CertCreateTime" + "$Le_RenewalDays" \* 24 \* 60 \* 60) - - Le_NextRenewTimeStr=$(_time2str "$Le_NextRenewTime") - _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr" - - Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400) - _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" - - _on_issue_success "$_post_hook" "$_renew_hook" - - if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then - _savedomainconf "Le_RealCertPath" "$_real_cert" - _savedomainconf "Le_RealCACertPath" "$_real_ca" - _savedomainconf "Le_RealKeyPath" "$_real_key" - _savedomainconf "Le_ReloadCmd" "$_reload_cmd" - _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" - _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd" - fi - -} - -#domain [isEcc] -renew() { - Le_Domain="$1" - if [ -z "$Le_Domain" ]; then - _usage "Usage: $PROJECT_ENTRY --renew -d domain.com [--ecc]" - return 1 - fi - - _isEcc="$2" - - _initpath "$Le_Domain" "$_isEcc" - - _info "$(__green "Renew: '$Le_Domain'")" - if [ ! -f "$DOMAIN_CONF" ]; then - _info "'$Le_Domain' is not a issued domain, skip." - return 0 - fi - - if [ "$Le_RenewalDays" ]; then - _savedomainconf Le_RenewalDays "$Le_RenewalDays" - fi - - . "$DOMAIN_CONF" - - if [ "$Le_API" ]; then - API="$Le_API" - #reload ca configs - ACCOUNT_KEY_PATH="" - ACCOUNT_JSON_PATH="" - CA_CONF="" - _debug3 "initpath again." - _initpath "$Le_Domain" "$_isEcc" - fi - - 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." - return "$RENEW_SKIP" - fi - - IS_RENEW="1" - 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" - res="$?" - if [ "$res" != "0" ]; then - return "$res" - fi - - if [ "$Le_DeployHook" ]; then - _deploy "$Le_Domain" "$Le_DeployHook" - res="$?" - fi - - IS_RENEW="" - - return "$res" -} - -#renewAll [stopRenewOnError] -renewAll() { - _initpath - _stopRenewOnError="$1" - _debug "_stopRenewOnError" "$_stopRenewOnError" - _ret="0" - - for di in "${CERT_HOME}"/*.*/; do - _debug di "$di" - if ! [ -d "$di" ]; then - _debug "Not directory, skip: $di" - continue - fi - d=$(basename "$di") - _debug d "$d" - ( - if _endswith "$d" "$ECC_SUFFIX"; then - _isEcc=$(echo "$d" | cut -d "$ECC_SEP" -f 2) - d=$(echo "$d" | cut -d "$ECC_SEP" -f 1) - fi - renew "$d" "$_isEcc" - ) - rc="$?" - _debug "Return code: $rc" - if [ "$rc" != "0" ]; then - if [ "$rc" = "$RENEW_SKIP" ]; then - _info "Skipped $d" - elif [ "$_stopRenewOnError" ]; then - _err "Error renew $d, stop now." - return "$rc" - else - _ret="$rc" - _err "Error renew $d, Go ahead to next one." - fi - fi - done - return "$_ret" -} - -#csr webroot -signcsr() { - _csrfile="$1" - _csrW="$2" - if [ -z "$_csrfile" ] || [ -z "$_csrW" ]; then - _usage "Usage: $PROJECT_ENTRY --signcsr --csr mycsr.csr -w /path/to/webroot/a.com/ " - return 1 - fi - - _initpath - - _csrsubj=$(_readSubjectFromCSR "$_csrfile") - if [ "$?" != "0" ]; then - _err "Can not read subject from csr: $_csrfile" - return 1 - fi - _debug _csrsubj "$_csrsubj" - - _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile") - if [ "$?" != "0" ]; then - _err "Can not read domain list from csr: $_csrfile" - return 1 - fi - _debug "_csrdomainlist" "$_csrdomainlist" - - if [ -z "$_csrsubj" ]; then - _csrsubj="$(_getfield "$_csrdomainlist" 1)" - _debug _csrsubj "$_csrsubj" - _csrdomainlist="$(echo "$_csrdomainlist" | cut -d , -f 2-)" - _debug "_csrdomainlist" "$_csrdomainlist" - fi - - if [ -z "$_csrsubj" ]; then - _err "Can not read subject from csr: $_csrfile" - return 1 - fi - - _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile") - if [ "$?" != "0" ] || [ -z "$_csrkeylength" ]; then - _err "Can not read key length from csr: $_csrfile" - return 1 - fi - - _initpath "$_csrsubj" "$_csrkeylength" - mkdir -p "$DOMAIN_PATH" - - _info "Copy csr to: $CSR_PATH" - cp "$_csrfile" "$CSR_PATH" - - issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength" - -} - -showcsr() { - _csrfile="$1" - _csrd="$2" - if [ -z "$_csrfile" ] && [ -z "$_csrd" ]; then - _usage "Usage: $PROJECT_ENTRY --showcsr --csr mycsr.csr" - return 1 - fi - - _initpath - - _csrsubj=$(_readSubjectFromCSR "$_csrfile") - if [ "$?" != "0" ] || [ -z "$_csrsubj" ]; then - _err "Can not read subject from csr: $_csrfile" - return 1 - fi - - _info "Subject=$_csrsubj" - - _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile") - if [ "$?" != "0" ]; then - _err "Can not read domain list from csr: $_csrfile" - return 1 - fi - _debug "_csrdomainlist" "$_csrdomainlist" - - _info "SubjectAltNames=$_csrdomainlist" - - _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile") - if [ "$?" != "0" ] || [ -z "$_csrkeylength" ]; then - _err "Can not read key length from csr: $_csrfile" - return 1 - fi - _info "KeyLength=$_csrkeylength" -} - -list() { - _raw="$1" - _initpath - - _sep="|" - if [ "$_raw" ]; then - printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Created${_sep}Renew" - for di in "${CERT_HOME}"/*.*/; do - if ! [ -d "$di" ]; then - _debug "Not directory, skip: $di" - continue - fi - d=$(basename "$di") - _debug d "$d" - ( - if _endswith "$d" "$ECC_SUFFIX"; then - _isEcc=$(echo "$d" | cut -d "$ECC_SEP" -f 2) - d=$(echo "$d" | cut -d "$ECC_SEP" -f 1) - fi - _initpath "$d" "$_isEcc" - if [ -f "$DOMAIN_CONF" ]; then - . "$DOMAIN_CONF" - printf "%s\n" "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr" - fi - ) - done - else - if _exists column; then - list "raw" | column -t -s "$_sep" - else - list "raw" | tr "$_sep" '\t' - fi - fi - -} - -_deploy() { - _d="$1" - _hooks="$2" - - for _d_api in $(echo "$_hooks" | tr ',' " "); do - _deployApi="$(_findHook "$_d" deploy "$_d_api")" - if [ -z "$_deployApi" ]; then - _err "The deploy hook $_d_api is not found." - return 1 - fi - _debug _deployApi "$_deployApi" - - if ! ( - if ! . "$_deployApi"; then - _err "Load file $_deployApi error. Please check your api file and try again." - return 1 - fi - - d_command="${_d_api}_deploy" - 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 "$_d" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then - _err "Error deploy for domain:$_d" - return 1 - fi - ); then - _err "Deploy error." - return 1 - else - _info "$(__green Success)" - fi - done -} - -#domain hooks -deploy() { - _d="$1" - _hooks="$2" - _isEcc="$3" - if [ -z "$_hooks" ]; then - _usage "Usage: $PROJECT_ENTRY --deploy -d domain.com --deploy-hook cpanel [--ecc] " - return 1 - fi - - _initpath "$_d" "$_isEcc" - if [ ! -d "$DOMAIN_PATH" ]; then - _err "Domain is not valid:'$_d'" - return 1 - fi - - . "$DOMAIN_CONF" - - _savedomainconf Le_DeployHook "$_hooks" - - _deploy "$_d" "$_hooks" -} - -installcert() { - _main_domain="$1" - if [ -z "$_main_domain" ]; then - _usage "Usage: $PROJECT_ENTRY --installcert -d domain.com [--ecc] [--certpath cert-file-path] [--keypath key-file-path] [--capath ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]" - return 1 - fi - - _real_cert="$2" - _real_key="$3" - _real_ca="$4" - _reload_cmd="$5" - _real_fullchain="$6" - _isEcc="$7" - - _initpath "$_main_domain" "$_isEcc" - if [ ! -d "$DOMAIN_PATH" ]; then - _err "Domain is not valid:'$_main_domain'" - return 1 - fi - - _savedomainconf "Le_RealCertPath" "$_real_cert" - _savedomainconf "Le_RealCACertPath" "$_real_ca" - _savedomainconf "Le_RealKeyPath" "$_real_key" - _savedomainconf "Le_ReloadCmd" "$_reload_cmd" - _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" - - _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd" -} - -#domain cert key ca fullchain reloadcmd backup-prefix -_installcert() { - _main_domain="$1" - _real_cert="$2" - _real_key="$3" - _real_ca="$4" - _real_fullchain="$5" - _reload_cmd="$6" - _backup_prefix="$7" - - if [ "$_real_cert" = "$NO_VALUE" ]; then - _real_cert="" - fi - if [ "$_real_key" = "$NO_VALUE" ]; then - _real_key="" - fi - if [ "$_real_ca" = "$NO_VALUE" ]; then - _real_ca="" - fi - if [ "$_reload_cmd" = "$NO_VALUE" ]; then - _reload_cmd="" - fi - if [ "$_real_fullchain" = "$NO_VALUE" ]; then - _real_fullchain="" - fi - - _backup_path="$DOMAIN_BACKUP_PATH/$_backup_prefix" - mkdir -p "$_backup_path" - - if [ "$_real_cert" ]; then - _info "Installing cert to:$_real_cert" - if [ -f "$_real_cert" ] && [ ! "$IS_RENEW" ]; then - cp "$_real_cert" "$_backup_path/cert.bak" - fi - cat "$CERT_PATH" >"$_real_cert" - fi - - if [ "$_real_ca" ]; then - _info "Installing CA to:$_real_ca" - if [ "$_real_ca" = "$_real_cert" ]; then - echo "" >>"$_real_ca" - cat "$CA_CERT_PATH" >>"$_real_ca" - else - if [ -f "$_real_ca" ] && [ ! "$IS_RENEW" ]; then - cp "$_real_ca" "$_backup_path/ca.bak" - fi - cat "$CA_CERT_PATH" >"$_real_ca" - fi - fi - - if [ "$_real_key" ]; then - _info "Installing key to:$_real_key" - if [ -f "$_real_key" ] && [ ! "$IS_RENEW" ]; then - cp "$_real_key" "$_backup_path/key.bak" - fi - cat "$CERT_KEY_PATH" >"$_real_key" - fi - - if [ "$_real_fullchain" ]; then - _info "Installing full chain to:$_real_fullchain" - if [ -f "$_real_fullchain" ] && [ ! "$IS_RENEW" ]; then - cp "$_real_fullchain" "$_backup_path/fullchain.bak" - fi - cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" - fi - - if [ "$_reload_cmd" ]; then - _info "Run reload cmd: $_reload_cmd" - if ( - export CERT_PATH - export CERT_KEY_PATH - export CA_CERT_PATH - export CERT_FULLCHAIN_PATH - cd "$DOMAIN_PATH" && eval "$_reload_cmd" - ); then - _info "$(__green "Reload success")" - else - _err "Reload error for :$Le_Domain" - fi - fi - -} - -#confighome -installcronjob() { - _c_home="$1" - _initpath - if ! _exists "crontab"; then - _err "crontab doesn't exist, so, we can not install cron jobs." - _err "All your certs will not be renewed automatically." - _err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday." - return 1 - fi - - _info "Installing cron job" - if ! crontab -l | grep "$PROJECT_ENTRY --cron"; then - if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then - lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY" - else - _err "Can not install cronjob, $PROJECT_ENTRY not found." - return 1 - fi - - if [ "$_c_home" ]; then - _c_entry="--config-home \"$_c_home\" " - fi - _t=$(_time) - random_minute=$(_math $_t % 60) - if _exists uname && uname -a | grep SunOS >/dev/null; then - crontab -l | { - cat - echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null" - } | crontab -- - else - crontab -l | { - cat - echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null" - } | crontab - - fi - fi - if [ "$?" != "0" ]; then - _err "Install cron job failed. You need to manually renew your certs." - _err "Or you can add cronjob by yourself:" - _err "$lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" - return 1 - fi -} - -uninstallcronjob() { - if ! _exists "crontab"; then - return - fi - _info "Removing cron job" - cr="$(crontab -l | grep "$PROJECT_ENTRY --cron")" - if [ "$cr" ]; then - if _exists uname && uname -a | grep solaris >/dev/null; then - crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab -- - else - crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab - - fi - LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')" - _info LE_WORKING_DIR "$LE_WORKING_DIR" - if _contains "$cr" "--config-home"; then - LE_CONFIG_HOME="$(echo "$cr" | cut -d ' ' -f 11 | tr -d '"')" - _debug LE_CONFIG_HOME "$LE_CONFIG_HOME" - fi - fi - _initpath - -} - -revoke() { - Le_Domain="$1" - if [ -z "$Le_Domain" ]; then - _usage "Usage: $PROJECT_ENTRY --revoke -d domain.com [--ecc]" - return 1 - fi - - _isEcc="$2" - - _initpath "$Le_Domain" "$_isEcc" - if [ ! -f "$DOMAIN_CONF" ]; then - _err "$Le_Domain is not a issued domain, skip." - return 1 - fi - - if [ ! -f "$CERT_PATH" ]; then - _err "Cert for $Le_Domain $CERT_PATH is not found, skip." - return 1 - fi - - cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _url_replace)" - - if [ -z "$cert" ]; then - _err "Cert for $Le_Domain is empty found, skip." - return 1 - fi - - data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" - uri="$API/acme/revoke-cert" - - if [ -f "$CERT_KEY_PATH" ]; then - _info "Try domain key first." - if _send_signed_request "$uri" "$data" "" "$CERT_KEY_PATH"; then - if [ -z "$response" ]; then - _info "Revoke success." - rm -f "$CERT_PATH" - return 0 - else - _err "Revoke error by domain key." - _err "$response" - fi - fi - else - _info "Domain key file doesn't exists." - fi - - _info "Try account key." - - if _send_signed_request "$uri" "$data" "" "$ACCOUNT_KEY_PATH"; then - if [ -z "$response" ]; then - _info "Revoke success." - rm -f "$CERT_PATH" - return 0 - else - _err "Revoke error." - _debug "$response" - fi - fi - return 1 -} - -#domain ecc -remove() { - Le_Domain="$1" - if [ -z "$Le_Domain" ]; then - _usage "Usage: $PROJECT_ENTRY --remove -d domain.com [--ecc]" - return 1 - fi - - _isEcc="$2" - - _initpath "$Le_Domain" "$_isEcc" - _removed_conf="$DOMAIN_CONF.removed" - if [ ! -f "$DOMAIN_CONF" ]; then - if [ -f "$_removed_conf" ]; then - _err "$Le_Domain is already removed, You can remove the folder by yourself: $DOMAIN_PATH" - else - _err "$Le_Domain is not a issued domain, skip." - fi - return 1 - fi - - if mv "$DOMAIN_CONF" "$_removed_conf"; then - _info "$Le_Domain is removed, the key and cert files are in $(__green $DOMAIN_PATH)" - _info "You can remove them by yourself." - return 0 - else - _err "Remove $Le_Domain failed." - return 1 - fi -} - -#domain vtype -_deactivate() { - _d_domain="$1" - _d_type="$2" - _initpath - - _d_i=0 - _d_max_retry=9 - while [ "$_d_i" -lt "$_d_max_retry" ]; do - _info "Deactivate: $_d_domain" - _d_i="$(_math $_d_i + 1)" - - if ! __get_domain_new_authz "$_d_domain"; then - _err "Can not get domain new authz token." - return 1 - fi - - authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")" - _debug "authzUri" "$authzUri" - - if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then - _err "new-authz error: $response" - return 1 - fi - - entry="$(printf "%s\n" "$response" | _egrep_o '{"type":"[^"]*","status":"valid","uri"[^}]*')" - _debug entry "$entry" - - if [ -z "$entry" ]; then - _info "No more valid entry found." - break - fi - - _vtype="$(printf "%s\n" "$entry" | _egrep_o '"type": *"[^"]*"' | cut -d : -f 2 | tr -d '"')" - _debug _vtype "$_vtype" - _info "Found $_vtype" - - uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')" - _debug uri "$uri" - - if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then - _info "Skip $_vtype" - continue - fi - - _info "Deactivate: $_vtype" - - if ! _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}"; then - _err "Can not deactivate $_vtype." - return 1 - fi - - _info "Deactivate: $_vtype success." - - done - _debug "$_d_i" - if [ "$_d_i" -lt "$_d_max_retry" ]; then - _info "Deactivated success!" - else - _err "Deactivate failed." - fi - -} - -deactivate() { - _d_domain_list="$1" - _d_type="$2" - _initpath - _debug _d_domain_list "$_d_domain_list" - if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then - _usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]" - return 1 - fi - for _d_dm in $(echo "$_d_domain_list" | tr ',' ' '); do - if [ -z "$_d_dm" ] || [ "$_d_dm" = "$NO_VALUE" ]; then - continue - fi - if ! _deactivate "$_d_dm" "$_d_type"; then - return 1 - fi - done -} - -# Detect profile file if not specified as environment variable -_detect_profile() { - if [ -n "$PROFILE" -a -f "$PROFILE" ]; then - echo "$PROFILE" - return - fi - - DETECTED_PROFILE='' - SHELLTYPE="$(basename "/$SHELL")" - - if [ "$SHELLTYPE" = "bash" ]; then - if [ -f "$HOME/.bashrc" ]; then - DETECTED_PROFILE="$HOME/.bashrc" - elif [ -f "$HOME/.bash_profile" ]; then - DETECTED_PROFILE="$HOME/.bash_profile" - fi - elif [ "$SHELLTYPE" = "zsh" ]; then - DETECTED_PROFILE="$HOME/.zshrc" - fi - - if [ -z "$DETECTED_PROFILE" ]; then - if [ -f "$HOME/.profile" ]; then - DETECTED_PROFILE="$HOME/.profile" - elif [ -f "$HOME/.bashrc" ]; then - DETECTED_PROFILE="$HOME/.bashrc" - elif [ -f "$HOME/.bash_profile" ]; then - DETECTED_PROFILE="$HOME/.bash_profile" - elif [ -f "$HOME/.zshrc" ]; then - DETECTED_PROFILE="$HOME/.zshrc" - fi - fi - - if [ ! -z "$DETECTED_PROFILE" ]; then - echo "$DETECTED_PROFILE" - fi -} - -_initconf() { - _initpath - if [ ! -f "$ACCOUNT_CONF_PATH" ]; then - echo " - -#LOG_FILE=\"$DEFAULT_LOG_FILE\" -#LOG_LEVEL=1 - -#AUTO_UPGRADE=\"1\" - -#NO_TIMESTAMP=1 - - " >"$ACCOUNT_CONF_PATH" - fi -} - -# nocron -_precheck() { - _nocron="$1" - - if ! _exists "curl" && ! _exists "wget"; then - _err "Please install curl or wget first, we need to access http resources." - return 1 - fi - - if [ -z "$_nocron" ]; then - if ! _exists "crontab"; then - _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." - _err "We need to set cron job to renew the certs automatically." - _err "Otherwise, your certs will not be able to be renewed automatically." - if [ -z "$FORCE" ]; then - _err "Please add '--force' and try install again to go without crontab." - _err "./$PROJECT_ENTRY --install --force" - return 1 - fi - fi - fi - - if ! _exists "$ACME_OPENSSL_BIN"; then - _err "Please install openssl first. ACME_OPENSSL_BIN=$ACME_OPENSSL_BIN" - _err "We need openssl to generate keys." - return 1 - fi - - if ! _exists "nc"; then - _err "It is recommended to install nc first, try to install 'nc' or 'netcat'." - _err "We use nc for standalone server if you use standalone mode." - _err "If you don't use standalone mode, just ignore this warning." - fi - - return 0 -} - -_setShebang() { - _file="$1" - _shebang="$2" - if [ -z "$_shebang" ]; then - _usage "Usage: file shebang" - return 1 - fi - cp "$_file" "$_file.tmp" - echo "$_shebang" >"$_file" - sed -n 2,99999p "$_file.tmp" >>"$_file" - rm -f "$_file.tmp" -} - -#confighome -_installalias() { - _c_home="$1" - _initpath - - _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env" - if [ "$_upgrading" ] && [ "$_upgrading" = "1" ]; then - echo "$(cat "$_envfile")" | sed "s|^LE_WORKING_DIR.*$||" >"$_envfile" - echo "$(cat "$_envfile")" | sed "s|^alias le.*$||" >"$_envfile" - echo "$(cat "$_envfile")" | sed "s|^alias le.sh.*$||" >"$_envfile" - fi - - if [ "$_c_home" ]; then - _c_entry=" --config-home '$_c_home'" - fi - - _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" - if [ "$_c_home" ]; then - _setopt "$_envfile" "export LE_CONFIG_HOME" "=" "\"$LE_CONFIG_HOME\"" - fi - _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" - - _profile="$(_detect_profile)" - if [ "$_profile" ]; then - _debug "Found profile: $_profile" - _info "Installing alias to '$_profile'" - _setopt "$_profile" ". \"$_envfile\"" - _info "OK, Close and reopen your terminal to start using $PROJECT_NAME" - else - _info "No profile is found, you will need to go into $LE_WORKING_DIR to use $PROJECT_NAME" - fi - - #for csh - _cshfile="$LE_WORKING_DIR/$PROJECT_ENTRY.csh" - _csh_profile="$HOME/.cshrc" - if [ -f "$_csh_profile" ]; then - _info "Installing alias to '$_csh_profile'" - _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" - if [ "$_c_home" ]; then - _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" - fi - _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" - _setopt "$_csh_profile" "source \"$_cshfile\"" - fi - - #for tcsh - _tcsh_profile="$HOME/.tcshrc" - if [ -f "$_tcsh_profile" ]; then - _info "Installing alias to '$_tcsh_profile'" - _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" - if [ "$_c_home" ]; then - _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" - fi - _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" - _setopt "$_tcsh_profile" "source \"$_cshfile\"" - fi - -} - -# nocron confighome -install() { - - if [ -z "$LE_WORKING_DIR" ]; then - LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" - fi - - _nocron="$1" - _c_home="$2" - if ! _initpath; then - _err "Install failed." - return 1 - fi - if [ "$_nocron" ]; then - _debug "Skip install cron job" - fi - - if ! _precheck "$_nocron"; then - _err "Pre-check failed, can not install." - return 1 - fi - - #convert from le - if [ -d "$HOME/.le" ]; then - for envfile in "le.env" "le.sh.env"; do - if [ -f "$HOME/.le/$envfile" ]; then - if grep "le.sh" "$HOME/.le/$envfile" >/dev/null; then - _upgrading="1" - _info "You are upgrading from le.sh" - _info "Renaming \"$HOME/.le\" to $LE_WORKING_DIR" - mv "$HOME/.le" "$LE_WORKING_DIR" - mv "$LE_WORKING_DIR/$envfile" "$LE_WORKING_DIR/$PROJECT_ENTRY.env" - break - fi - fi - done - fi - - _info "Installing to $LE_WORKING_DIR" - - if ! mkdir -p "$LE_WORKING_DIR"; then - _err "Can not create working dir: $LE_WORKING_DIR" - return 1 - fi - - chmod 700 "$LE_WORKING_DIR" - - if ! mkdir -p "$LE_CONFIG_HOME"; then - _err "Can not create config dir: $LE_CONFIG_HOME" - return 1 - fi - - chmod 700 "$LE_CONFIG_HOME" - - cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" - - if [ "$?" != "0" ]; then - _err "Install failed, can not copy $PROJECT_ENTRY" - return 1 - fi - - _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY" - - _installalias "$_c_home" - - for subf in $_SUB_FOLDERS; do - if [ -d "$subf" ]; then - mkdir -p "$LE_WORKING_DIR/$subf" - cp "$subf"/* "$LE_WORKING_DIR"/"$subf"/ - fi - done - - if [ ! -f "$ACCOUNT_CONF_PATH" ]; then - _initconf - fi - - if [ "$_DEFAULT_ACCOUNT_CONF_PATH" != "$ACCOUNT_CONF_PATH" ]; then - _setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\"" - fi - - if [ "$_DEFAULT_CERT_HOME" != "$CERT_HOME" ]; then - _saveaccountconf "CERT_HOME" "$CERT_HOME" - fi - - if [ "$_DEFAULT_ACCOUNT_KEY_PATH" != "$ACCOUNT_KEY_PATH" ]; then - _saveaccountconf "ACCOUNT_KEY_PATH" "$ACCOUNT_KEY_PATH" - fi - - if [ -z "$_nocron" ]; then - installcronjob "$_c_home" - fi - - if [ -z "$NO_DETECT_SH" ]; then - #Modify shebang - if _exists bash; then - _info "Good, bash is found, so change the shebang to use bash as preferred." - _shebang='#!'"$(env bash -c "command -v bash")" - _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" - for subf in $_SUB_FOLDERS; do - if [ -d "$LE_WORKING_DIR/$subf" ]; then - for _apifile in "$LE_WORKING_DIR/$subf/"*.sh; do - _setShebang "$_apifile" "$_shebang" - done - fi - done - fi - fi - - _info OK -} - -# nocron -uninstall() { - _nocron="$1" - if [ -z "$_nocron" ]; then - uninstallcronjob - fi - _initpath - - _uninstallalias - - rm -f "$LE_WORKING_DIR/$PROJECT_ENTRY" - _info "The keys and certs are in \"$(__green "$LE_CONFIG_HOME")\", you can remove them by yourself." - -} - -_uninstallalias() { - _initpath - - _profile="$(_detect_profile)" - if [ "$_profile" ]; then - _info "Uninstalling alias from: '$_profile'" - text="$(cat "$_profile")" - echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" >"$_profile" - fi - - _csh_profile="$HOME/.cshrc" - if [ -f "$_csh_profile" ]; then - _info "Uninstalling alias from: '$_csh_profile'" - text="$(cat "$_csh_profile")" - echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_csh_profile" - fi - - _tcsh_profile="$HOME/.tcshrc" - if [ -f "$_tcsh_profile" ]; then - _info "Uninstalling alias from: '$_csh_profile'" - text="$(cat "$_tcsh_profile")" - echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_tcsh_profile" - fi - -} - -cron() { - IN_CRON=1 - _initpath - if [ "$AUTO_UPGRADE" = "1" ]; then - export LE_WORKING_DIR - ( - if ! upgrade; then - _err "Cron:Upgrade failed!" - return 1 - fi - ) - . "$LE_WORKING_DIR/$PROJECT_ENTRY" >/dev/null - - if [ -t 1 ]; then - __INTERACTIVE="1" - fi - - _info "Auto upgraded to: $VER" - fi - renewAll - _ret="$?" - IN_CRON="" - exit $_ret -} - -version() { - echo "$PROJECT" - echo "v$VER" -} - -showhelp() { - _initpath - version - echo "Usage: $PROJECT_ENTRY command ...[parameters].... -Commands: - --help, -h Show this help message. - --version, -v Show version info. - --install Install $PROJECT_NAME to your system. - --uninstall Uninstall $PROJECT_NAME, and uninstall the cron job. - --upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT. - --issue Issue a cert. - --signcsr Issue a cert from an existing csr. - --deploy Deploy the cert to your server. - --install-cert Install the issued cert to apache/nginx or any other server. - --renew, -r Renew a cert. - --renew-all Renew all the certs. - --revoke Revoke a cert. - --remove Remove the cert from $PROJECT - --list List all the certs. - --showcsr Show the content of a csr. - --install-cronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. - --uninstall-cronjob Uninstall the cron job. The 'uninstall' command can do this automatically. - --cron Run cron job to renew all the certs. - --toPkcs Export the certificate and key to a pfx file. - --toPkcs8 Convert to pkcs8 format. - --update-account Update account info. - --register-account Register account key. - --create-account-key Create an account private key, professional use. - --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. - --staging, --test Use staging server, just for test. - --debug Output debug info. - --output-insecure Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for secure. - --webroot, -w /path/to/webroot Specifies the web root folder for web root mode. - --standalone Use standalone mode. - --stateless Use stateless mode, see: $_STATELESS_WIKI - --tls Use standalone tls mode. - --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: - - --certpath /path/to/real/cert/file After issue/renew, the cert will be copied to this path. - --keypath /path/to/real/key/file After issue/renew, the key will be copied to this path. - --capath /path/to/real/ca/file After issue/renew, the intermediate cert will be copied to this path. - --fullchainpath /path/to/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. - --home Specifies the home dir for $PROJECT_NAME . - --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. - --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. - --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. - --tlsport Specifies the standalone tls 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. - --listraw Only used for '--list' command, list the certs in raw format. - --stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal. - --insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted. - --ca-bundle Specifices the path to the CA certificate bundle to verify api server's certificate. - --nocron Only valid for '--install' command, which means: do not install the default cron job. In this case, the certs will not be renewed automatically. - --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR' - --csr Specifies the input csr. - --pre-hook Command to be run before obtaining any certificates. - --post-hook Command to be run after attempting to obtain/renew certificates. No matter the obain/renew is success or failed. - --renew-hook Command to be run once for each successfully renewed certificate. - --deploy-hook The hook file to deploy cert - --ocsp-must-staple, --ocsp Generate ocsp must Staple extension. - --auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future. - --listen-v4 Force standalone/tls server to listen at ipv4. - --listen-v6 Force standalone/tls server to listen at ipv6. - --openssl-bin Specifies a custom openssl bin location. - --use-wget Force to use wget, if you have both curl and wget installed. - " -} - -# nocron -_installOnline() { - _info "Installing from online archive." - _nocron="$1" - if [ ! "$BRANCH" ]; then - BRANCH="master" - fi - - target="$PROJECT/archive/$BRANCH.tar.gz" - _info "Downloading $target" - localname="$BRANCH.tar.gz" - if ! _get "$target" >$localname; then - _err "Download error." - return 1 - fi - ( - _info "Extracting $localname" - if ! (tar xzf $localname || gtar xzf $localname); then - _err "Extraction error." - exit 1 - fi - - cd "$PROJECT_NAME-$BRANCH" - chmod +x $PROJECT_ENTRY - if ./$PROJECT_ENTRY install "$_nocron"; then - _info "Install success!" - fi - - cd .. - - rm -rf "$PROJECT_NAME-$BRANCH" - rm -f "$localname" - ) -} - -upgrade() { - if ( - _initpath - export LE_WORKING_DIR - cd "$LE_WORKING_DIR" - _installOnline "nocron" - ); then - _info "Upgrade success!" - exit 0 - else - _err "Upgrade failed!" - exit 1 - fi -} - -_processAccountConf() { - if [ "$_useragent" ]; then - _saveaccountconf "USER_AGENT" "$_useragent" - elif [ "$USER_AGENT" ] && [ "$USER_AGENT" != "$DEFAULT_USER_AGENT" ]; then - _saveaccountconf "USER_AGENT" "$USER_AGENT" - fi - - if [ "$_accountemail" ]; then - _saveaccountconf "ACCOUNT_EMAIL" "$_accountemail" - elif [ "$ACCOUNT_EMAIL" ] && [ "$ACCOUNT_EMAIL" != "$DEFAULT_ACCOUNT_EMAIL" ]; then - _saveaccountconf "ACCOUNT_EMAIL" "$ACCOUNT_EMAIL" - fi - - if [ "$_openssl_bin" ]; then - _saveaccountconf "ACME_OPENSSL_BIN" "$_openssl_bin" - elif [ "$ACME_OPENSSL_BIN" ] && [ "$ACME_OPENSSL_BIN" != "$DEFAULT_OPENSSL_BIN" ]; then - _saveaccountconf "ACME_OPENSSL_BIN" "$ACME_OPENSSL_BIN" - fi - - if [ "$_auto_upgrade" ]; then - _saveaccountconf "AUTO_UPGRADE" "$_auto_upgrade" - elif [ "$AUTO_UPGRADE" ]; then - _saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE" - fi - - if [ "$_use_wget" ]; then - _saveaccountconf "ACME_USE_WGET" "$_use_wget" - elif [ "$ACME_USE_WGET" ]; then - _saveaccountconf "ACME_USE_WGET" "$ACME_USE_WGET" - fi - -} - -_process() { - _CMD="" - _domain="" - _altdomains="$NO_VALUE" - _webroot="" - _keylength="" - _accountkeylength="" - _certpath="" - _keypath="" - _capath="" - _fullchainpath="" - _reloadcmd="" - _password="" - _accountconf="" - _useragent="" - _accountemail="" - _accountkey="" - _certhome="" - _confighome="" - _httpport="" - _tlsport="" - _dnssleep="" - _listraw="" - _stopRenewOnError="" - #_insecure="" - _ca_bundle="" - _nocron="" - _ecc="" - _csr="" - _pre_hook="" - _post_hook="" - _renew_hook="" - _deploy_hook="" - _logfile="" - _log="" - _local_address="" - _log_level="" - _auto_upgrade="" - _listen_v4="" - _listen_v6="" - _openssl_bin="" - _syslog="" - _use_wget="" - while [ ${#} -gt 0 ]; do - case "${1}" in - - --help | -h) - showhelp - return - ;; - --version | -v) - version - return - ;; - --install) - _CMD="install" - ;; - --uninstall) - _CMD="uninstall" - ;; - --upgrade) - _CMD="upgrade" - ;; - --issue) - _CMD="issue" - ;; - --deploy) - _CMD="deploy" - ;; - --signcsr) - _CMD="signcsr" - ;; - --showcsr) - _CMD="showcsr" - ;; - --installcert | -i | --install-cert) - _CMD="installcert" - ;; - --renew | -r) - _CMD="renew" - ;; - --renewAll | --renewall | --renew-all) - _CMD="renewAll" - ;; - --revoke) - _CMD="revoke" - ;; - --remove) - _CMD="remove" - ;; - --list) - _CMD="list" - ;; - --installcronjob | --install-cronjob) - _CMD="installcronjob" - ;; - --uninstallcronjob | --uninstall-cronjob) - _CMD="uninstallcronjob" - ;; - --cron) - _CMD="cron" - ;; - --toPkcs) - _CMD="toPkcs" - ;; - --toPkcs8) - _CMD="toPkcs8" - ;; - --createAccountKey | --createaccountkey | -cak | --create-account-key) - _CMD="createAccountKey" - ;; - --createDomainKey | --createdomainkey | -cdk | --create-domain-key) - _CMD="createDomainKey" - ;; - --createCSR | --createcsr | -ccr) - _CMD="createCSR" - ;; - --deactivate) - _CMD="deactivate" - ;; - --updateaccount | --update-account) - _CMD="updateaccount" - ;; - --registeraccount | --register-account) - _CMD="registeraccount" - ;; - --domain | -d) - _dvalue="$2" - - if [ "$_dvalue" ]; then - if _startswith "$_dvalue" "-"; then - _err "'$_dvalue' is not a valid domain for parameter '$1'" - return 1 - fi - if _is_idn "$_dvalue" && ! _exists idn; then - _err "It seems that $_dvalue is an IDN( Internationalized Domain Names), please install 'idn' command first." - return 1 - fi - - if [ -z "$_domain" ]; then - _domain="$_dvalue" - else - if [ "$_altdomains" = "$NO_VALUE" ]; then - _altdomains="$_dvalue" - else - _altdomains="$_altdomains,$_dvalue" - fi - fi - fi - - shift - ;; - - --force | -f) - FORCE="1" - ;; - --staging | --test) - STAGE="1" - ;; - --debug) - if [ -z "$2" ] || _startswith "$2" "-"; then - DEBUG="$DEBUG_LEVEL_DEFAULT" - else - DEBUG="$2" - shift - fi - ;; - --output-insecure) - export OUTPUT_INSECURE=1 - ;; - --webroot | -w) - wvalue="$2" - if [ -z "$_webroot" ]; then - _webroot="$wvalue" - else - _webroot="$_webroot,$wvalue" - fi - shift - ;; - --standalone) - wvalue="$NO_VALUE" - if [ -z "$_webroot" ]; then - _webroot="$wvalue" - else - _webroot="$_webroot,$wvalue" - fi - ;; - --stateless) - wvalue="$MODE_STATELESS" - if [ -z "$_webroot" ]; then - _webroot="$wvalue" - else - _webroot="$_webroot,$wvalue" - fi - ;; - --local-address) - lvalue="$2" - _local_address="$_local_address$lvalue," - shift - ;; - --apache) - wvalue="apache" - if [ -z "$_webroot" ]; then - _webroot="$wvalue" - else - _webroot="$_webroot,$wvalue" - fi - ;; - --nginx) - wvalue="$NGINX" - if [ -z "$_webroot" ]; then - _webroot="$wvalue" - else - _webroot="$_webroot,$wvalue" - fi - ;; - --tls) - wvalue="$W_TLS" - if [ -z "$_webroot" ]; then - _webroot="$wvalue" - else - _webroot="$_webroot,$wvalue" - fi - ;; - --dns) - wvalue="dns" - if ! _startswith "$2" "-"; then - wvalue="$2" - shift - fi - if [ -z "$_webroot" ]; then - _webroot="$wvalue" - else - _webroot="$_webroot,$wvalue" - fi - ;; - --dnssleep) - _dnssleep="$2" - Le_DNSSleep="$_dnssleep" - shift - ;; - - --keylength | -k) - _keylength="$2" - shift - ;; - --accountkeylength | -ak) - _accountkeylength="$2" - shift - ;; - - --certpath) - _certpath="$2" - shift - ;; - --keypath) - _keypath="$2" - shift - ;; - --capath) - _capath="$2" - shift - ;; - --fullchainpath) - _fullchainpath="$2" - shift - ;; - --reloadcmd | --reloadCmd) - _reloadcmd="$2" - shift - ;; - --password) - _password="$2" - shift - ;; - --accountconf) - _accountconf="$2" - ACCOUNT_CONF_PATH="$_accountconf" - shift - ;; - --home) - LE_WORKING_DIR="$2" - shift - ;; - --certhome | --cert-home) - _certhome="$2" - CERT_HOME="$_certhome" - shift - ;; - --config-home) - _confighome="$2" - LE_CONFIG_HOME="$_confighome" - shift - ;; - --useragent) - _useragent="$2" - USER_AGENT="$_useragent" - shift - ;; - --accountemail) - _accountemail="$2" - ACCOUNT_EMAIL="$_accountemail" - shift - ;; - --accountkey) - _accountkey="$2" - ACCOUNT_KEY_PATH="$_accountkey" - shift - ;; - --days) - _days="$2" - Le_RenewalDays="$_days" - shift - ;; - --httpport) - _httpport="$2" - Le_HTTPPort="$_httpport" - shift - ;; - --tlsport) - _tlsport="$2" - Le_TLSPort="$_tlsport" - shift - ;; - - --listraw) - _listraw="raw" - ;; - --stopRenewOnError | --stoprenewonerror | -se) - _stopRenewOnError="1" - ;; - --insecure) - #_insecure="1" - HTTPS_INSECURE="1" - ;; - --ca-bundle) - _ca_bundle="$(_readlink -f "$2")" - CA_BUNDLE="$_ca_bundle" - shift - ;; - --nocron) - _nocron="1" - ;; - --ecc) - _ecc="isEcc" - ;; - --csr) - _csr="$2" - shift - ;; - --pre-hook) - _pre_hook="$2" - shift - ;; - --post-hook) - _post_hook="$2" - shift - ;; - --renew-hook) - _renew_hook="$2" - shift - ;; - --deploy-hook) - if [ -z "$2" ] || _startswith "$2" "-"; then - _usage "Please specify a value for '--deploy-hook'" - return 1 - fi - _deploy_hook="$_deploy_hook$2," - shift - ;; - --ocsp-must-staple | --ocsp) - Le_OCSP_Staple="1" - ;; - --log | --logfile) - _log="1" - _logfile="$2" - if _startswith "$_logfile" '-'; then - _logfile="" - else - shift - fi - LOG_FILE="$_logfile" - if [ -z "$LOG_LEVEL" ]; then - LOG_LEVEL="$DEFAULT_LOG_LEVEL" - fi - ;; - --log-level) - _log_level="$2" - LOG_LEVEL="$_log_level" - shift - ;; - --syslog) - if ! _startswith "$2" '-'; then - _syslog="$2" - shift - fi - if [ -z "$_syslog" ]; then - _syslog="$SYSLOG_LEVEL_DEFAULT" - fi - ;; - --auto-upgrade) - _auto_upgrade="$2" - if [ -z "$_auto_upgrade" ] || _startswith "$_auto_upgrade" '-'; then - _auto_upgrade="1" - else - shift - fi - AUTO_UPGRADE="$_auto_upgrade" - ;; - --listen-v4) - _listen_v4="1" - Le_Listen_V4="$_listen_v4" - ;; - --listen-v6) - _listen_v6="1" - Le_Listen_V6="$_listen_v6" - ;; - --openssl-bin) - _openssl_bin="$2" - ACME_OPENSSL_BIN="$_openssl_bin" - shift - ;; - --use-wget) - _use_wget="1" - ACME_USE_WGET="1" - ;; - *) - _err "Unknown parameter : $1" - return 1 - ;; - esac - - shift 1 - done - - if [ "${_CMD}" != "install" ]; then - __initHome - if [ "$_log" ]; then - if [ -z "$_logfile" ]; then - _logfile="$DEFAULT_LOG_FILE" - fi - fi - if [ "$_logfile" ]; then - _saveaccountconf "LOG_FILE" "$_logfile" - LOG_FILE="$_logfile" - fi - - if [ "$_log_level" ]; then - _saveaccountconf "LOG_LEVEL" "$_log_level" - LOG_LEVEL="$_log_level" - fi - - if [ "$_syslog" ]; then - if _exists logger; then - if [ "$_syslog" = "0" ]; then - _clearaccountconf "SYS_LOG" - else - _saveaccountconf "SYS_LOG" "$_syslog" - fi - SYS_LOG="$_syslog" - else - _err "The 'logger' command is not found, can not enable syslog." - _clearaccountconf "SYS_LOG" - SYS_LOG="" - fi - fi - - _processAccountConf - fi - - _debug2 LE_WORKING_DIR "$LE_WORKING_DIR" - - if [ "$DEBUG" ]; then - version - fi - - case "${_CMD}" in - install) install "$_nocron" "$_confighome" ;; - uninstall) uninstall "$_nocron" ;; - upgrade) upgrade ;; - issue) - issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" - ;; - deploy) - deploy "$_domain" "$_deploy_hook" "$_ecc" - ;; - signcsr) - signcsr "$_csr" "$_webroot" - ;; - showcsr) - showcsr "$_csr" "$_domain" - ;; - installcert) - installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_ecc" - ;; - renew) - renew "$_domain" "$_ecc" - ;; - renewAll) - renewAll "$_stopRenewOnError" - ;; - revoke) - revoke "$_domain" "$_ecc" - ;; - remove) - remove "$_domain" "$_ecc" - ;; - deactivate) - deactivate "$_domain,$_altdomains" - ;; - registeraccount) - registeraccount "$_accountkeylength" - ;; - updateaccount) - updateaccount - ;; - list) - list "$_listraw" - ;; - installcronjob) installcronjob "$_confighome" ;; - uninstallcronjob) uninstallcronjob ;; - cron) cron ;; - toPkcs) - toPkcs "$_domain" "$_password" "$_ecc" - ;; - toPkcs8) - toPkcs8 "$_domain" "$_ecc" - ;; - createAccountKey) - createAccountKey "$_accountkeylength" - ;; - createDomainKey) - createDomainKey "$_domain" "$_keylength" - ;; - createCSR) - createCSR "$_domain" "$_altdomains" "$_ecc" - ;; - - *) - if [ "$_CMD" ]; then - _err "Invalid command: $_CMD" - fi - showhelp - return 1 - ;; - esac - _ret="$?" - if [ "$_ret" != "0" ]; then - return $_ret - fi - - if [ "${_CMD}" = "install" ]; then - if [ "$_log" ]; then - if [ -z "$LOG_FILE" ]; then - LOG_FILE="$DEFAULT_LOG_FILE" - fi - _saveaccountconf "LOG_FILE" "$LOG_FILE" - fi - - if [ "$_log_level" ]; then - _saveaccountconf "LOG_LEVEL" "$_log_level" - fi - - if [ "$_syslog" ]; then - if _exists logger; then - if [ "$_syslog" = "0" ]; then - _clearaccountconf "SYS_LOG" - else - _saveaccountconf "SYS_LOG" "$_syslog" - fi - else - _err "The 'logger' command is not found, can not enable syslog." - _clearaccountconf "SYS_LOG" - SYS_LOG="" - fi - fi - - _processAccountConf - fi - -} - -if [ "$INSTALLONLINE" ]; then - INSTALLONLINE="" - _installOnline - exit -fi - -main() { - [ -z "$1" ] && showhelp && return - if _startswith "$1" '-'; then _process "$@"; else "$@"; fi -} - -main "$@" diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php index b5cfcd0b3..8e9e9eab2 100755 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php +++ b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php @@ -343,7 +343,7 @@ function run_acme_account_registration($acctObj, $certObj, $modelObj) } // Let acme client generate a new account key - $acmecmd = "/usr/local/opnsense/scripts/OPNsense/AcmeClient/acme.sh " + $acmecmd = "/usr/local/sbin/acme.sh " . implode(" ", $acme_args) . " " . "--createAccountKey " . "--accountkeylength 4096 " @@ -388,7 +388,7 @@ function run_acme_account_registration($acctObj, $certObj, $modelObj) } // Run acme client to register the account - $acmecmd = "/usr/local/opnsense/scripts/OPNsense/AcmeClient/acme.sh " + $acmecmd = "/usr/local/sbin/acme.sh " . implode(" ", $acme_args) . " " . "--registeraccount " . "--log-level 2 " @@ -692,7 +692,7 @@ function run_acme_validation($certObj, $valObj, $acctObj) // Run acme client // NOTE: We "export" certificates to our own directory, so we don't have to deal // with domain names in filesystem, but instead can use the ID of our certObj. - $acmecmd = "/usr/local/opnsense/scripts/OPNsense/AcmeClient/acme.sh " + $acmecmd = "/usr/local/sbin/acme.sh " . implode(" ", $acme_args) . " " . "--${acme_action} " . "--domain " . (string)$certObj->name . " " @@ -759,7 +759,7 @@ function revoke_cert($certObj, $valObj, $acctObj) // Run acme client // NOTE: We "export" certificates to our own directory, so we don't have to deal // with domain names in filesystem, but instead can use the ID of our certObj. - $acmecmd = "/usr/local/opnsense/scripts/OPNsense/AcmeClient/acme.sh " + $acmecmd = "/usr/local/sbin/acme.sh " . implode(" ", $acme_args) . " " . "--revoke " . "--domain " . (string)$certObj->name . " " diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_ad.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_ad.sh deleted file mode 100755 index fc4a664be..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_ad.sh +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/env sh - -# -#AD_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" - -#This is the Alwaysdata api wrapper for acme.sh -# -#Author: Paul Koppen -#Report Bugs here: https://github.com/wpk-/acme.sh - -AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1" - -######## Public functions ##################### - -#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_ad_add() { - fulldomain=$1 - txtvalue=$2 - - if [ -z "$AD_API_KEY" ]; then - AD_API_KEY="" - _err "You didn't specify the AD api key yet." - _err "Please create you key and try again." - return 1 - fi - - _saveaccountconf AD_API_KEY "$AD_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" - - _ad_tmpl_json="{\"domain\":$_domain_id,\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\"}" - - if _ad_rest POST "record/" "$_ad_tmpl_json" && [ -z "$response" ]; then - _info "txt record updated success." - return 0 - fi - - return 1 -} - -#fulldomain txtvalue -dns_ad_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" - _ad_rest GET "record/?domain=$_domain_id&name=$_sub_domain" - - if [ -n "$response" ]; then - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) - _debug record_id "$record_id" - if [ -z "$record_id" ]; then - _err "Can not get record id to remove." - return 1 - fi - if _ad_rest DELETE "record/$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 _ad_rest GET "domain/"; 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 -_ad_rest() { - mtd="$1" - ep="$2" - data="$3" - - _debug mtd "$mtd" - _debug ep "$ep" - - export _H1="Accept: application/json" - export _H2="Content-Type: application/json" - - if [ "$mtd" != "GET" ]; then - # both POST and DELETE. - _debug data "$data" - response="$(_post "$data" "$AD_API_URL/$ep" "" "$mtd")" - else - response="$(_get "$AD_API_URL/$ep")" - fi - - if [ "$?" != "0" ]; then - _err "error $ep" - return 1 - fi - _debug2 response "$response" - return 0 -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_ali.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_ali.sh deleted file mode 100755 index f796f076c..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_ali.sh +++ /dev/null @@ -1,187 +0,0 @@ -#!/usr/bin/env sh - -Ali_API="https://alidns.aliyuncs.com/" - -#Ali_Key="LTqIA87hOKdjevsf5" -#Ali_Secret="0p5EYueFNq501xnCPzKNbx6K51qPH2" - -#Usage: dns_ali_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_ali_add() { - fulldomain=$1 - txtvalue=$2 - - if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then - Ali_Key="" - Ali_Secret="" - _err "You don't specify aliyun api key and secret yet." - return 1 - fi - - #save the api key and secret to the account conf file. - _saveaccountconf Ali_Key "$Ali_Key" - _saveaccountconf Ali_Secret "$Ali_Secret" - - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - return 1 - fi - - _debug "Add record" - _add_record_query "$_domain" "$_sub_domain" "$txtvalue" && _ali_rest "Add record" -} - -dns_ali_rm() { - fulldomain=$1 - _clean -} - -#################### Private functions below ################################## - -_get_root() { - domain=$1 - i=2 - p=1 - while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) - if [ -z "$h" ]; then - #not valid - return 1 - fi - - _describe_records_query "$h" - if ! _ali_rest "Get root" "ignore"; then - return 1 - fi - - if _contains "$response" "PageNumber"; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - _debug _sub_domain "$_sub_domain" - _domain="$h" - _debug _domain "$_domain" - return 0 - fi - p="$i" - i=$(_math "$i" + 1) - done - return 1 -} - -_ali_rest() { - signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | tr -d " ")" | _base64) - signature=$(_ali_urlencode "$signature") - url="$Ali_API?$query&Signature=$signature" - - if ! response="$(_get "$url")"; then - _err "Error <$1>" - return 1 - fi - - if [ -z "$2" ]; then - message="$(printf "%s" "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" - if [ -n "$message" ]; then - _err "$message" - return 1 - fi - fi - - _debug2 response "$response" - return 0 -} - -_ali_urlencode() { - _str="$1" - _str_len=${#_str} - _u_i=1 - while [ "$_u_i" -le "$_str_len" ]; do - _str_c="$(printf "%s" "$_str" | cut -c "$_u_i")" - case $_str_c in [a-zA-Z0-9.~_-]) - printf "%s" "$_str_c" - ;; - *) - printf "%%%02X" "'$_str_c" - ;; - esac - _u_i="$(_math "$_u_i" + 1)" - done -} - -_ali_nonce() { - #_head_n 1 UPSERT$fulldomainTXT300\"$txtvalue\"" - - if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then - _info "txt record updated success." - return 0 - fi - - return 1 -} - -#fulldomain txtvalue -dns_aws_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" - - _aws_tmpl_xml="DELETE\"$txtvalue\"$fulldomain.TXT300" - - if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then - _info "txt record deleted success." - return 0 - fi - - return 1 - -} - -#################### Private functions below ################################## - -_get_root() { - domain=$1 - i=2 - p=1 - - if aws_rest GET "2013-04-01/hostedzone"; then - _debug "response" "$response" - while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) - if [ -z "$h" ]; then - #not valid - return 1 - fi - - if _contains "$response" "$h."; then - hostedzone="$(echo "$response" | sed 's//#&/g' | tr '#' '\n' | _egrep_o "[^<]*<.Id>$h.<.Name>.*<.HostedZone>")" - _debug hostedzone "$hostedzone" - if [ -z "$hostedzone" ]; then - _err "Error, can not get hostedzone." - return 1 - fi - _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*<.Id>" | head -n 1 | _egrep_o ">.*<" | 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 -aws_rest() { - mtd="$1" - ep="$2" - qsr="$3" - data="$4" - - _debug mtd "$mtd" - _debug ep "$ep" - _debug qsr "$qsr" - _debug data "$data" - - CanonicalURI="/$ep" - _debug2 CanonicalURI "$CanonicalURI" - - CanonicalQueryString="$qsr" - _debug2 CanonicalQueryString "$CanonicalQueryString" - - RequestDate="$(date -u +"%Y%m%dT%H%M%SZ")" - _debug2 RequestDate "$RequestDate" - - #RequestDate="20161120T141056Z" ############## - - export _H1="x-amz-date: $RequestDate" - - aws_host="$AWS_HOST" - CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n" - SignedHeaders="host;x-amz-date" - if [ -n "$AWS_SESSION_TOKEN" ]; then - export _H2="x-amz-security-token: $AWS_SESSION_TOKEN" - CanonicalHeaders="${CanonicalHeaders}x-amz-security-token:$AWS_SESSION_TOKEN\n" - SignedHeaders="${SignedHeaders};x-amz-security-token" - fi - _debug2 CanonicalHeaders "$CanonicalHeaders" - _debug2 SignedHeaders "$SignedHeaders" - - RequestPayload="$data" - _debug2 RequestPayload "$RequestPayload" - - Hash="sha256" - - CanonicalRequest="$mtd\n$CanonicalURI\n$CanonicalQueryString\n$CanonicalHeaders\n$SignedHeaders\n$(printf "%s" "$RequestPayload" | _digest "$Hash" hex)" - _debug2 CanonicalRequest "$CanonicalRequest" - - HashedCanonicalRequest="$(printf "$CanonicalRequest%s" | _digest "$Hash" hex)" - _debug2 HashedCanonicalRequest "$HashedCanonicalRequest" - - Algorithm="AWS4-HMAC-SHA256" - _debug2 Algorithm "$Algorithm" - - RequestDateOnly="$(echo "$RequestDate" | cut -c 1-8)" - _debug2 RequestDateOnly "$RequestDateOnly" - - Region="us-east-1" - Service="route53" - - CredentialScope="$RequestDateOnly/$Region/$Service/aws4_request" - _debug2 CredentialScope "$CredentialScope" - - StringToSign="$Algorithm\n$RequestDate\n$CredentialScope\n$HashedCanonicalRequest" - - _debug2 StringToSign "$StringToSign" - - kSecret="AWS4$AWS_SECRET_ACCESS_KEY" - - #kSecret="wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ############################ - - _secure_debug2 kSecret "$kSecret" - - kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")" - _secure_debug2 kSecretH "$kSecretH" - - kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" - _debug2 kDateH "$kDateH" - - kRegionH="$(printf "$Region%s" | _hmac "$Hash" "$kDateH" hex)" - _debug2 kRegionH "$kRegionH" - - kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)" - _debug2 kServiceH "$kServiceH" - - kSigningH="$(printf "aws4_request%s" | _hmac "$Hash" "$kServiceH" hex)" - _debug2 kSigningH "$kSigningH" - - signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)" - _debug2 signature "$signature" - - Authorization="$Algorithm Credential=$AWS_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature" - _debug2 Authorization "$Authorization" - - _H3="Authorization: $Authorization" - _debug _H3 "$_H3" - - url="$AWS_URL/$ep" - - if [ "$mtd" = "GET" ]; then - response="$(_get "$url")" - else - response="$(_post "$data" "$url")" - fi - - _ret="$?" - if [ "$_ret" = "0" ]; then - if _contains "$response" "/dev/null; then - _err "Error" - return 1 - fi - - count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) - _debug count "$count" - if [ "$count" = "0" ]; then - _info "Adding record" - if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then - _info "Added, OK" - return 0 - else - _err "Add txt record error." - return 1 - fi - fi - _err "Add txt record error." - else - _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) - _debug "record_id" "$record_id" - - _cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}" - if [ "$?" = "0" ]; then - _info "Updated, OK" - return 0 - fi - _err "Update error" - return 1 - fi - -} - -#fulldomain txtvalue -dns_cf_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" - _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain&content=$txtvalue" - - if ! printf "%s" "$response" | grep \"success\":true >/dev/null; then - _err "Error" - return 1 - fi - - count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) - _debug count "$count" - if [ "$count" = "0" ]; then - _info "Don't need to remove." - else - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) - _debug "record_id" "$record_id" - if [ -z "$record_id" ]; then - _err "Can not get record id to remove." - return 1 - fi - if ! _cf_rest DELETE "zones/$_domain_id/dns_records/$record_id"; then - _err "Delete record error." - return 1 - fi - _contains "$response" '"success":true' - fi - -} - -#################### Private functions below ################################## -#_acme-challenge.www.domain.com -#returns -# _sub_domain=_acme-challenge.www -# _domain=domain.com -# _domain_id=sdjkglgdfewsdfg -_get_root() { - domain=$1 - 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 ! _cf_rest GET "zones?name=$h"; then - return 1 - fi - - if _contains "$response" "\"name\":\"$h\"" >/dev/null; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | 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 - return 1 -} - -_cf_rest() { - m=$1 - ep="$2" - data="$3" - _debug "$ep" - - export _H1="X-Auth-Email: $CF_Email" - export _H2="X-Auth-Key: $CF_Key" - export _H3="Content-Type: application/json" - - if [ "$m" != "GET" ]; then - _debug data "$data" - response="$(_post "$data" "$CF_Api/$ep" "" "$m")" - else - response="$(_get "$CF_Api/$ep")" - fi - - if [ "$?" != "0" ]; then - _err "error $ep" - return 1 - fi - _debug2 response "$response" - return 0 -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_cx.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_cx.sh deleted file mode 100755 index 2b6d56915..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_cx.sh +++ /dev/null @@ -1,216 +0,0 @@ -#!/usr/bin/env sh - -# Cloudxns.com Domain api -# -#CX_Key="1234" -# -#CX_Secret="sADDsdasdgdsf" - -CX_Api="https://www.cloudxns.net/api2" - -#REST_API -######## Public functions ##################### - -#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_cx_add() { - fulldomain=$1 - txtvalue=$2 - - if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ]; then - CX_Key="" - CX_Secret="" - _err "You don't specify cloudxns.com api key or secret yet." - _err "Please create you key and try again." - return 1 - fi - - REST_API="$CX_Api" - - #save the api key and email to the account conf file. - _saveaccountconf CX_Key "$CX_Key" - _saveaccountconf CX_Secret "$CX_Secret" - - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - _err "invalid domain" - return 1 - fi - - existing_records "$_domain" "$_sub_domain" - _debug count "$count" - if [ "$?" != "0" ]; then - _err "Error get existing records." - return 1 - fi - - if [ "$count" = "0" ]; then - add_record "$_domain" "$_sub_domain" "$txtvalue" - else - update_record "$_domain" "$_sub_domain" "$txtvalue" - fi - - if [ "$?" = "0" ]; then - return 0 - fi - return 1 -} - -#fulldomain -dns_cx_rm() { - fulldomain=$1 - REST_API="$CX_Api" - if _get_root "$fulldomain"; then - record_id="" - existing_records "$_domain" "$_sub_domain" - if ! [ "$record_id" = "" ]; then - _rest DELETE "record/$record_id/$_domain_id" "{}" - _info "Deleted record ${fulldomain}" - fi - fi -} - -#usage: root sub -#return if the sub record already exists. -#echos the existing records count. -# '0' means doesn't exist -existing_records() { - _debug "Getting txt records" - root=$1 - sub=$2 - count=0 - if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then - return 1 - fi - - seg=$(printf "%s\n" "$response" | _egrep_o '"record_id":[^{]*host":"'"$_sub_domain"'"[^}]*\}') - _debug seg "$seg" - if [ -z "$seg" ]; then - return 0 - fi - - if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then - count=1 - record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1) - _debug record_id "$record_id" - return 0 - fi - -} - -#add the txt record. -#usage: root sub txtvalue -add_record() { - root=$1 - sub=$2 - txtvalue=$3 - fulldomain="$sub.$root" - - _info "Adding record" - - if ! _rest POST "record" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then - return 1 - fi - - return 0 -} - -#update the txt record -#Usage: root sub txtvalue -update_record() { - root=$1 - sub=$2 - txtvalue=$3 - fulldomain="$sub.$root" - - _info "Updating record" - - if _rest PUT "record/$record_id" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then - return 0 - fi - - 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 - i=2 - p=1 - - if ! _rest GET "domain"; then - return 1 - fi - - 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."; then - seg=$(printf "%s\n" "$response" | _egrep_o '"id":[^{]*"'"$h"'."[^}]*}') - _debug seg "$seg" - _domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") - _debug _domain_id "$_domain_id" - if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - _debug _sub_domain "$_sub_domain" - _domain="$h" - _debug _domain "$_domain" - return 0 - fi - return 1 - fi - p="$i" - i=$(_math "$i" + 1) - done - return 1 -} - -#Usage: method URI data -_rest() { - m=$1 - ep="$2" - _debug ep "$ep" - url="$REST_API/$ep" - _debug url "$url" - - cdate=$(date -u "+%Y-%m-%d %H:%M:%S UTC") - _debug cdate "$cdate" - - data="$3" - _debug data "$data" - - sec="$CX_Key$url$data$cdate$CX_Secret" - _debug sec "$sec" - hmac=$(printf "%s" "$sec" | _digest md5 hex) - _debug hmac "$hmac" - - export _H1="API-KEY: $CX_Key" - export _H2="API-REQUEST-DATE: $cdate" - export _H3="API-HMAC: $hmac" - export _H4="Content-Type: application/json" - - if [ "$data" ]; then - response="$(_post "$data" "$url" "" "$m")" - else - response="$(_get "$url")" - fi - - if [ "$?" != "0" ]; then - _err "error $ep" - return 1 - fi - _debug2 response "$response" - if ! _contains "$response" '"message":"success"'; then - return 1 - fi - return 0 -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_cyon.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_cyon.sh deleted file mode 100755 index c096d8b07..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_cyon.sh +++ /dev/null @@ -1,328 +0,0 @@ -#!/usr/bin/env sh - -######## -# Custom cyon.ch DNS API for use with [acme.sh](https://github.com/Neilpang/acme.sh) -# -# Usage: acme.sh --issue --dns dns_cyon -d www.domain.com -# -# Dependencies: -# ------------- -# - oathtool (When using 2 Factor Authentication) -# -# Issues: -# ------- -# Any issues / questions / suggestions can be posted here: -# https://github.com/noplanman/cyon-api/issues -# -# Author: Armando Lüscher -######## - -dns_cyon_add() { - _cyon_load_credentials \ - && _cyon_load_parameters "$@" \ - && _cyon_print_header "add" \ - && _cyon_login \ - && _cyon_change_domain_env \ - && _cyon_add_txt \ - && _cyon_logout -} - -dns_cyon_rm() { - _cyon_load_credentials \ - && _cyon_load_parameters "$@" \ - && _cyon_print_header "delete" \ - && _cyon_login \ - && _cyon_change_domain_env \ - && _cyon_delete_txt \ - && _cyon_logout -} - -######################### -### PRIVATE FUNCTIONS ### -######################### - -_cyon_load_credentials() { - # Convert loaded password to/from base64 as needed. - if [ "${CY_Password_B64}" ]; then - CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64 "multiline")" - elif [ "${CY_Password}" ]; then - CY_Password_B64="$(printf "%s" "${CY_Password}" | _base64)" - fi - - if [ -z "${CY_Username}" ] || [ -z "${CY_Password}" ]; then - # Dummy entries to satify script checker. - CY_Username="" - CY_Password="" - CY_OTP_Secret="" - - _err "" - _err "You haven't set your cyon.ch login credentials yet." - _err "Please set the required cyon environment variables." - _err "" - return 1 - fi - - # Save the login credentials to the account.conf file. - _debug "Save credentials to account.conf" - _saveaccountconf CY_Username "${CY_Username}" - _saveaccountconf CY_Password_B64 "$CY_Password_B64" - if [ ! -z "${CY_OTP_Secret}" ]; then - _saveaccountconf CY_OTP_Secret "$CY_OTP_Secret" - else - _clearaccountconf CY_OTP_Secret - fi -} - -_cyon_is_idn() { - _idn_temp="$(printf "%s" "${1}" | tr -d "0-9a-zA-Z.,-_")" - _idn_temp2="$(printf "%s" "${1}" | grep -o "xn--")" - [ "$_idn_temp" ] || [ "$_idn_temp2" ] -} - -_cyon_load_parameters() { - # Read the required parameters to add the TXT entry. - # shellcheck disable=SC2018,SC2019 - fulldomain="$(printf "%s" "${1}" | tr "A-Z" "a-z")" - fulldomain_idn="${fulldomain}" - - # Special case for IDNs, as cyon needs a domain environment change, - # which uses the "pretty" instead of the punycode version. - if _cyon_is_idn "${fulldomain}"; then - if ! _exists idn; then - _err "Please install idn to process IDN names." - _err "" - return 1 - fi - - fulldomain="$(idn -u "${fulldomain}")" - fulldomain_idn="$(idn -a "${fulldomain}")" - fi - - _debug fulldomain "${fulldomain}" - _debug fulldomain_idn "${fulldomain_idn}" - - txtvalue="${2}" - _debug txtvalue "${txtvalue}" - - # This header is required for curl calls. - _H1="X-Requested-With: XMLHttpRequest" - export _H1 -} - -_cyon_print_header() { - if [ "${1}" = "add" ]; then - _info "" - _info "+---------------------------------------------+" - _info "| Adding DNS TXT entry to your cyon.ch domain |" - _info "+---------------------------------------------+" - _info "" - _info " * Full Domain: ${fulldomain}" - _info " * TXT Value: ${txtvalue}" - _info "" - elif [ "${1}" = "delete" ]; then - _info "" - _info "+-------------------------------------------------+" - _info "| Deleting DNS TXT entry from your cyon.ch domain |" - _info "+-------------------------------------------------+" - _info "" - _info " * Full Domain: ${fulldomain}" - _info "" - fi -} - -_cyon_get_cookie_header() { - printf "Cookie: %s" "$(grep "cyon=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'cyon=[^;]*;' | tr -d ';')" -} - -_cyon_login() { - _info " - Logging in..." - - username_encoded="$(printf "%s" "${CY_Username}" | _url_encode)" - password_encoded="$(printf "%s" "${CY_Password}" | _url_encode)" - - login_url="https://my.cyon.ch/auth/index/dologin-async" - login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")" - - login_response="$(_post "$login_data" "$login_url")" - _debug login_response "${login_response}" - - # Bail if login fails. - if [ "$(printf "%s" "${login_response}" | _cyon_get_response_success)" != "success" ]; then - _err " $(printf "%s" "${login_response}" | _cyon_get_response_message)" - _err "" - return 1 - fi - - _info " success" - - # NECESSARY!! Load the main page after login, to get the new cookie. - _H2="$(_cyon_get_cookie_header)" - export _H2 - - _get "https://my.cyon.ch/" >/dev/null - - # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. - - # 2FA authentication with OTP? - if [ ! -z "${CY_OTP_Secret}" ]; then - _info " - Authorising with OTP code..." - - if ! _exists oathtool; then - _err "Please install oathtool to use 2 Factor Authentication." - _err "" - return 1 - fi - - # Get OTP code with the defined secret. - otp_code="$(oathtool --base32 --totp "${CY_OTP_Secret}" 2>/dev/null)" - - login_otp_url="https://my.cyon.ch/auth/multi-factor/domultifactorauth-async" - login_otp_data="totpcode=${otp_code}&pathname=%2F&rememberme=0" - - login_otp_response="$(_post "$login_otp_data" "$login_otp_url")" - _debug login_otp_response "${login_otp_response}" - - # Bail if OTP authentication fails. - if [ "$(printf "%s" "${login_otp_response}" | _cyon_get_response_success)" != "success" ]; then - _err " $(printf "%s" "${login_otp_response}" | _cyon_get_response_message)" - _err "" - return 1 - fi - - _info " success" - fi - - _info "" -} - -_cyon_logout() { - _info " - Logging out..." - - _get "https://my.cyon.ch/auth/index/dologout" >/dev/null - - _info " success" - _info "" -} - -_cyon_change_domain_env() { - _info " - Changing domain environment..." - - # Get the "example.com" part of the full domain name. - domain_env="$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/')" - _debug "Changing domain environment to ${domain_env}" - - gloo_item_key="$(_get "https://my.cyon.ch/domain/" | tr '\n' ' ' | sed -E -e "s/.*data-domain=\"${domain_env}\"[^<]*data-itemkey=\"([^\"]*).*/\1/")" - _debug gloo_item_key "${gloo_item_key}" - - domain_env_url="https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/${gloo_item_key}" - - domain_env_response="$(_get "${domain_env_url}")" - _debug domain_env_response "${domain_env_response}" - - if ! _cyon_check_if_2fa_missed "${domain_env_response}"; then return 1; fi - - domain_env_success="$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2)" - - # Bail if domain environment change fails. - if [ "${domain_env_success}" != "true" ]; then - _err " $(printf "%s" "${domain_env_response}" | _cyon_get_response_message)" - _err "" - return 1 - fi - - _info " success" - _info "" -} - -_cyon_add_txt() { - _info " - Adding DNS TXT entry..." - - add_txt_url="https://my.cyon.ch/domain/dnseditor/add-record-async" - add_txt_data="zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}" - - add_txt_response="$(_post "$add_txt_data" "$add_txt_url")" - _debug add_txt_response "${add_txt_response}" - - if ! _cyon_check_if_2fa_missed "${add_txt_response}"; then return 1; fi - - add_txt_message="$(printf "%s" "${add_txt_response}" | _cyon_get_response_message)" - add_txt_status="$(printf "%s" "${add_txt_response}" | _cyon_get_response_status)" - - # Bail if adding TXT entry fails. - if [ "${add_txt_status}" != "true" ]; then - _err " ${add_txt_message}" - _err "" - return 1 - fi - - _info " success (TXT|${fulldomain_idn}.|${txtvalue})" - _info "" -} - -_cyon_delete_txt() { - _info " - Deleting DNS TXT entry..." - - list_txt_url="https://my.cyon.ch/domain/dnseditor/list-async" - - list_txt_response="$(_get "${list_txt_url}" | sed -e 's/data-hash/\\ndata-hash/g')" - _debug list_txt_response "${list_txt_response}" - - if ! _cyon_check_if_2fa_missed "${list_txt_response}"; then return 1; fi - - # Find and delete all acme challenge entries for the $fulldomain. - _dns_entries="$(printf "%b\n" "${list_txt_response}" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p')" - - printf "%s" "${_dns_entries}" | while read -r _hash _identifier; do - dns_type="$(printf "%s" "$_identifier" | cut -d'|' -f1)" - dns_domain="$(printf "%s" "$_identifier" | cut -d'|' -f2)" - - if [ "${dns_type}" != "TXT" ] || [ "${dns_domain}" != "${fulldomain_idn}." ]; then - continue - fi - - hash_encoded="$(printf "%s" "${_hash}" | _url_encode)" - identifier_encoded="$(printf "%s" "${_identifier}" | _url_encode)" - - delete_txt_url="https://my.cyon.ch/domain/dnseditor/delete-record-async" - delete_txt_data="$(printf "%s" "hash=${hash_encoded}&identifier=${identifier_encoded}")" - - delete_txt_response="$(_post "$delete_txt_data" "$delete_txt_url")" - _debug delete_txt_response "${delete_txt_response}" - - if ! _cyon_check_if_2fa_missed "${delete_txt_response}"; then return 1; fi - - delete_txt_message="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_message)" - delete_txt_status="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_status)" - - # Skip if deleting TXT entry fails. - if [ "${delete_txt_status}" != "true" ]; then - _err " ${delete_txt_message} (${_identifier})" - else - _info " success (${_identifier})" - fi - done - - _info " done" - _info "" -} - -_cyon_get_response_message() { - _egrep_o '"message":"[^"]*"' | cut -d : -f 2 | tr -d '"' -} - -_cyon_get_response_status() { - _egrep_o '"status":\w*' | cut -d : -f 2 -} - -_cyon_get_response_success() { - _egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"' -} - -_cyon_check_if_2fa_missed() { - # Did we miss the 2FA? - if test "${1#*multi_factor_form}" != "${1}"; then - _err " Missed OTP authentication!" - _err "" - return 1 - fi -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_do.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_do.sh deleted file mode 100755 index 3a2f8f495..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_do.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env sh - -# DNS API for Domain-Offensive / Resellerinterface / Domainrobot - -# Report bugs at https://github.com/seidler2547/acme.sh/issues - -# set these environment variables to match your customer ID and password: -# DO_PID="KD-1234567" -# DO_PW="cdfkjl3n2" - -DO_URL="https://soap.resellerinterface.de/" - -######## Public functions ##################### - -#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_do_add() { - fulldomain=$1 - txtvalue=$2 - if _dns_do_authenticate; then - _info "Adding TXT record to ${_domain} as ${fulldomain}" - _dns_do_soap createRR origin "${_domain}" name "${fulldomain}" type TXT data "${txtvalue}" ttl 300 - if _contains "${response}" '>success<'; then - return 0 - fi - _err "Could not create resource record, check logs" - fi - return 1 -} - -#fulldomain -dns_do_rm() { - fulldomain=$1 - if _dns_do_authenticate; then - if _dns_do_list_rrs; then - _dns_do_had_error=0 - for _rrid in ${_rr_list}; do - _info "Deleting resource record $_rrid for $_domain" - _dns_do_soap deleteRR origin "${_domain}" rrid "${_rrid}" - if ! _contains "${response}" '>success<'; then - _dns_do_had_error=1 - _err "Could not delete resource record for ${_domain}, id ${_rrid}" - fi - done - return $_dns_do_had_error - fi - fi - return 1 -} - -#################### Private functions below ################################## -_dns_do_authenticate() { - _info "Authenticating as ${DO_PID}" - _dns_do_soap authPartner partner "${DO_PID}" password "${DO_PW}" - if _contains "${response}" '>success<'; then - _get_root "$fulldomain" - _debug "_domain $_domain" - return 0 - else - _err "Authentication failed, are DO_PID and DO_PW set correctly?" - fi - return 1 -} - -_dns_do_list_rrs() { - _dns_do_soap getRRList origin "${_domain}" - if ! _contains "${response}" 'SOAP-ENC:Array'; then - _err "getRRList origin ${_domain} failed" - return 1 - fi - _rr_list="$(echo "${response}" \ - | tr -d "\n\r\t" \ - | sed -e 's//\n/g' \ - | grep ">$(_regexcape "$fulldomain")" \ - | sed -e 's/<\/item>/\n/g' \ - | grep '>id[0-9]{1,16}<' \ - | tr -d '><')" - [ "${_rr_list}" ] -} - -_dns_do_soap() { - func="$1" - shift - # put the parameters to xml - body="" - while [ "$1" ]; do - _k="$1" - shift - _v="$1" - shift - body="$body<$_k>$_v" - done - body="$body" - _debug2 "SOAP request ${body}" - - # build SOAP XML - _xml=' - - '"$body"' -' - - # set SOAP headers - export _H1="SOAPAction: ${DO_URL}#${func}" - - if ! response="$(_post "${_xml}" "${DO_URL}")"; then - _err "Error <$1>" - return 1 - fi - _debug2 "SOAP response $response" - - # retrieve cookie header - _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)" - export _H2 - - return 0 -} - -_get_root() { - domain=$1 - i=1 - - _dns_do_soap getDomainList - _all_domains="$(echo "${response}" \ - | tr -d "\n\r\t " \ - | _egrep_o 'domain]+>[^<]+' \ - | sed -e 's/^domain<\/key>]*>//g')" - - while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) - if [ -z "$h" ]; then - return 1 - fi - - if _contains "${_all_domains}" "^$(_regexcape "$h")\$"; then - _domain="$h" - return 0 - fi - - i=$(_math $i + 1) - done - _debug "$domain not found" - - return 1 -} - -_regexcape() { - echo "$1" | sed -e 's/\([]\.$*^[]\)/\\\1/g' -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_dp.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_dp.sh deleted file mode 100755 index 301a1f6cc..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_dp.sh +++ /dev/null @@ -1,223 +0,0 @@ -#!/usr/bin/env sh - -# Dnspod.cn Domain api -# -#DP_Id="1234" -# -#DP_Key="sADDsdasdgdsf" - -REST_API="https://dnsapi.cn" - -######## Public functions ##################### - -#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_dp_add() { - fulldomain=$1 - txtvalue=$2 - - if [ -z "$DP_Id" ] || [ -z "$DP_Key" ]; then - DP_Id="" - DP_Key="" - _err "You don't specify dnspod api key and key id yet." - _err "Please create you key and try again." - return 1 - fi - - #save the api key and email to the account conf file. - _saveaccountconf DP_Id "$DP_Id" - _saveaccountconf DP_Key "$DP_Key" - - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - _err "invalid domain" - return 1 - fi - - existing_records "$_domain" "$_sub_domain" - _debug count "$count" - if [ "$?" != "0" ]; then - _err "Error get existing records." - return 1 - fi - - if [ "$count" = "0" ]; then - add_record "$_domain" "$_sub_domain" "$txtvalue" - else - update_record "$_domain" "$_sub_domain" "$txtvalue" - fi -} - -#fulldomain txtvalue -dns_dp_rm() { - fulldomain=$1 - txtvalue=$2 - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - _err "invalid domain" - return 1 - fi - - if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain"; then - _err "Record.Lis error." - return 1 - fi - - if _contains "$response" 'No records'; then - _info "Don't need to remove." - return 0 - fi - - record_id=$(echo "$response" | _egrep_o '{[^{]*"value":"'"$txtvalue"'"' | cut -d , -f 1 | cut -d : -f 2 | tr -d \") - _debug record_id "$record_id" - if [ -z "$record_id" ]; then - _err "Can not get record id." - return 1 - fi - - if ! _rest POST "Record.Remove" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&record_id=$record_id"; then - _err "Record.Remove error." - return 1 - fi - - _contains "$response" "Action completed successful" - -} - -#usage: root sub -#return if the sub record already exists. -#echos the existing records count. -# '0' means doesn't exist -existing_records() { - _debug "Getting txt records" - root=$1 - sub=$2 - - if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&domain_id=$_domain_id&sub_domain=$_sub_domain"; then - return 1 - fi - - if _contains "$response" 'No records'; then - count=0 - return 0 - fi - - if _contains "$response" "Action completed successful"; then - count=$(printf "%s" "$response" | grep -c 'TXT' | tr -d ' ') - record_id=$(printf "%s" "$response" | grep '^' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1) - _debug record_id "$record_id" - return 0 - else - _err "get existing records error." - return 1 - fi - - count=0 -} - -#add the txt record. -#usage: root sub txtvalue -add_record() { - root=$1 - sub=$2 - txtvalue=$3 - fulldomain="$sub.$root" - - _info "Adding record" - - if ! _rest POST "Record.Create" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认"; then - return 1 - fi - - if _contains "$response" "Action completed successful"; then - - return 0 - fi - - return 1 #error -} - -#update the txt record -#Usage: root sub txtvalue -update_record() { - root=$1 - sub=$2 - txtvalue=$3 - fulldomain="$sub.$root" - - _info "Updating record" - - if ! _rest POST "Record.Modify" "login_token=$DP_Id,$DP_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认&record_id=$record_id"; then - return 1 - fi - - if _contains "$response" "Action completed successful"; then - - return 0 - fi - - return 1 #error -} - -#################### Private functions below ################################## -#_acme-challenge.www.domain.com -#returns -# _sub_domain=_acme-challenge.www -# _domain=domain.com -# _domain_id=sdjkglgdfewsdfg -_get_root() { - domain=$1 - i=2 - p=1 - while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) - if [ -z "$h" ]; then - #not valid - return 1 - fi - - if ! _rest POST "Domain.Info" "login_token=$DP_Id,$DP_Key&format=json&domain=$h"; then - return 1 - fi - - if _contains "$response" "Action completed successful"; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") - _debug _domain_id "$_domain_id" - if [ "$_domain_id" ]; then - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - _debug _sub_domain "$_sub_domain" - _domain="$h" - _debug _domain "$_domain" - return 0 - fi - return 1 - fi - p="$i" - i=$(_math "$i" + 1) - done - return 1 -} - -#Usage: method URI data -_rest() { - m="$1" - ep="$2" - data="$3" - _debug "$ep" - url="$REST_API/$ep" - - _debug url "$url" - - if [ "$m" = "GET" ]; then - response="$(_get "$url" | tr -d '\r')" - else - _debug2 data "$data" - response="$(_post "$data" "$url" | tr -d '\r')" - fi - - if [ "$?" != "0" ]; then - _err "error $ep" - return 1 - fi - _debug2 response "$response" - return 0 -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_freedns.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_freedns.sh deleted file mode 100755 index 25bed1f24..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_freedns.sh +++ /dev/null @@ -1,375 +0,0 @@ -#!/usr/bin/env sh - -#This file name is "dns_freedns.sh" -#So, here must be a method dns_freedns_add() -#Which will be called by acme.sh to add the txt record to your api system. -#returns 0 means success, otherwise error. -# -#Author: David Kerr -#Report Bugs here: https://github.com/dkerr64/acme.sh -# -######## Public functions ##################### - -# Export FreeDNS userid and password in folowing variables... -# FREEDNS_User=username -# FREEDNS_Password=password -# login cookie is saved in acme account config file so userid / pw -# need to be set only when changed. - -#Usage: dns_freedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_freedns_add() { - fulldomain="$1" - txtvalue="$2" - - _info "Add TXT record using FreeDNS" - _debug "fulldomain: $fulldomain" - _debug "txtvalue: $txtvalue" - - if [ -z "$FREEDNS_User" ] || [ -z "$FREEDNS_Password" ]; then - FREEDNS_User="" - FREEDNS_Password="" - if [ -z "$FREEDNS_COOKIE" ]; then - _err "You did not specify the FreeDNS username and password yet." - _err "Please export as FREEDNS_User / FREEDNS_Password and try again." - return 1 - fi - using_cached_cookies="true" - else - FREEDNS_COOKIE="$(_freedns_login "$FREEDNS_User" "$FREEDNS_Password")" - if [ -z "$FREEDNS_COOKIE" ]; then - return 1 - fi - using_cached_cookies="false" - fi - - _debug "FreeDNS login cookies: $FREEDNS_COOKIE (cached = $using_cached_cookies)" - - _saveaccountconf FREEDNS_COOKIE "$FREEDNS_COOKIE" - - # split our full domain name into two parts... - i="$(echo "$fulldomain" | tr '.' ' ' | wc -w)" - i="$(_math "$i" - 1)" - top_domain="$(echo "$fulldomain" | cut -d. -f "$i"-100)" - i="$(_math "$i" - 1)" - sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" - - # Sometimes FreeDNS does not reurn 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 - # load the page and obtain our domain ID - attempts=2 - while [ "$attempts" -gt "0" ]; do - attempts="$(_math "$attempts" - 1)" - - htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" - if [ "$?" != "0" ]; then - if [ "$using_cached_cookies" = "true" ]; then - _err "Has your FreeDNS username and password channged? If so..." - _err "Please export as FREEDNS_User / FREEDNS_Password and try again." - fi - return 1 - 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 - subdomain_csv="$(echo "$htmlpage" \ - | grep -i -e ']*>/\n/Ig' \ - | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ - | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ - | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ - | grep 'edit.php?' \ - | grep "$top_domain")" - # The above beauty ends with striping out rows that do not have an - # href to edit.php and do not have the top domain we are looking for. - # So all we should be left with is CSV of table of subdomains we are - # interested in. - - # Now we have to read through this table and extract the data we need - lines="$(echo "$subdomain_csv" | wc -l)" - nl=' -' - i=0 - found=0 - while [ "$i" -lt "$lines" ]; do - i="$(_math "$i" + 1)" - line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")" - tmp="$(echo "$line" | cut -d ',' -f 1)" - if [ $found = 0 ] && _startswith "$tmp" "$top_domain"; then - # this line will contain DNSdomainid for the top_domain - DNSdomainid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*domain_id=//;s/>.*//')" - found=1 - else - # lines contain DNS records for all subdomains - DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')" - DNStype="$(echo "$line" | cut -d ',' -f 3)" - if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then - DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')" - # Now get current value for the TXT record. This method may - # not produce accurate results as the value field is truncated - # on this webpage. To get full value we would need to load - # another page. However we don't really need this so long as - # there is only one TXT record for the acme chalenge subdomain. - DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')" - if [ $found != 0 ]; then - break - # we are breaking out of the loop at the first match of DNS name - # and DNS type (if we are past finding the domainid). This assumes - # that there is only ever one TXT record for the LetsEncrypt/acme - # challenge subdomain. This seems to be a reasonable assumption - # as the acme client deletes the TXT record on successful validation. - fi - else - DNSname="" - DNStype="" - fi - fi - done - - _debug "DNSname: $DNSname DNStype: $DNStype DNSdomainid: $DNSdomainid DNSdataid: $DNSdataid" - _debug "DNSvalue: $DNSvalue" - - if [ -z "$DNSdomainid" ]; then - # If domain ID is empty then something went wrong (top level - # domain not found at FreeDNS). - if [ "$attempts" = "0" ]; then - # exhausted maximum retry attempts - _debug "$htmlpage" - _debug "$subdomain_csv" - _err "Domain $top_domain not found at FreeDNS" - return 1 - fi - else - # break out of the 'retry' loop... we have found our domain ID - break - fi - _info "Domain $top_domain not found at FreeDNS" - _info "Retry loading subdomain page ($attempts attempts remaining)" - done - - if [ -z "$DNSdataid" ]; then - # If data ID is empty then specific subdomain does not exist yet, need - # to create it this should always be the case as the acme client - # deletes the entry after domain is validated. - _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" - return $? - else - if [ "$txtvalue" = "$DNSvalue" ]; then - # if value in TXT record matches value requested then DNS record - # does not need to be updated. But... - # Testing value match fails. Website is truncating the value field. - # So for now we will always go down the else path. Though in theory - # should never come here anyway as the acme client deletes - # the TXT record on successful validation, so we should not even - # have found a TXT record !! - _info "No update necessary for $fulldomain at FreeDNS" - return 0 - else - # Delete the old TXT record (with the wrong value) - _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid" - if [ "$?" = "0" ]; then - # And add in new TXT record with the value provided - _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" - fi - return $? - fi - fi - return 0 -} - -#Usage: fulldomain txtvalue -#Remove the txt record after validation. -dns_freedns_rm() { - fulldomain="$1" - txtvalue="$2" - - _info "Delete TXT record using FreeDNS" - _debug "fulldomain: $fulldomain" - _debug "txtvalue: $txtvalue" - - # Need to read cookie from conf file again in case new value set - # during login to FreeDNS when TXT record was created. - # acme.sh does not have a _readaccountconf() fuction - FREEDNS_COOKIE="$(_read_conf "$ACCOUNT_CONF_PATH" "FREEDNS_COOKIE")" - _debug "FreeDNS login cookies: $FREEDNS_COOKIE" - - # Sometimes FreeDNS does not reurn 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 - # load the page and obtain our TXT record. - attempts=2 - while [ "$attempts" -gt "0" ]; do - attempts="$(_math "$attempts" - 1)" - - htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" - if [ "$?" != "0" ]; then - return 1 - 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 - subdomain_csv="$(echo "$htmlpage" \ - | grep -i -e ']*>/\n/Ig' \ - | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' \ - | sed 's/^]*>\|<\/\?T[DH][^>]*>$//Ig' \ - | sed 's/<\/T[DH][^>]*>]*>/,/Ig' \ - | grep 'edit.php?' \ - | grep "$fulldomain")" - # The above beauty ends with striping out rows that do not have an - # href to edit.php and do not have the domain name we are looking for. - # So all we should be left with is CSV of table of subdomains we are - # interested in. - - # Now we have to read through this table and extract the data we need - lines="$(echo "$subdomain_csv" | wc -l)" - nl=' -' - i=0 - found=0 - while [ "$i" -lt "$lines" ]; do - i="$(_math "$i" + 1)" - line="$(echo "$subdomain_csv" | cut -d "$nl" -f "$i")" - DNSname="$(echo "$line" | cut -d ',' -f 2 | sed 's/^[^>]*>//;s/<\/a>.*//')" - DNStype="$(echo "$line" | cut -d ',' -f 3)" - if [ "$DNSname" = "$fulldomain" ] && [ "$DNStype" = "TXT" ]; then - DNSdataid="$(echo "$line" | cut -d ',' -f 2 | sed 's/^.*data_id=//;s/>.*//')" - DNSvalue="$(echo "$line" | cut -d ',' -f 4 | sed 's/^[^"]*"//;s/".*//;s/<\/td>.*//')" - _debug "DNSvalue: $DNSvalue" - # if [ "$DNSvalue" = "$txtvalue" ]; then - # Testing value match fails. Website is truncating the value - # field. So for now we will assume that there is only one TXT - # field for the sub domain and just delete it. Currently this - # is a safe assumption. - _freedns_delete_txt_record "$FREEDNS_COOKIE" "$DNSdataid" - return $? - # fi - fi - done - done - - # If we get this far we did not find a match (after two attempts) - # Not necessarily an error, but log anyway. - _debug2 "$subdomain_csv" - _info "Cannot delete TXT record for $fulldomain/$txtvalue. Does not exist at FreeDNS" - return 0 -} - -#################### Private functions below ################################## - -# usage: _freedns_login username password -# print string "cookie=value" etc. -# returns 0 success -_freedns_login() { - export _H1="Accept-Language:en-US" - username="$1" - password="$2" - url="https://freedns.afraid.org/zc.php?step=2" - - _debug "Login to FreeDNS as user $username" - - htmlpage="$(_post "username=$(printf '%s' "$username" | _url_encode)&password=$(printf '%s' "$password" | _url_encode)&submit=Login&action=auth" "$url")" - - if [ "$?" != "0" ]; then - _err "FreeDNS login failed for user $username bad RC from _post" - return 1 - fi - - cookies="$(grep -i '^Set-Cookie.*dns_cookie.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" - - # if cookies is not empty then logon successful - if [ -z "$cookies" ]; then - _debug "$htmlpage" - _err "FreeDNS login failed for user $username. Check $HTTP_HEADER file" - return 1 - fi - - printf "%s" "$cookies" - return 0 -} - -# usage _freedns_retrieve_subdomain_page login_cookies -# echo page retrieved (html) -# returns 0 success -_freedns_retrieve_subdomain_page() { - export _H1="Cookie:$1" - export _H2="Accept-Language:en-US" - url="https://freedns.afraid.org/subdomain/" - - _debug "Retrieve subdmoain page from FreeDNS" - - htmlpage="$(_get "$url")" - - if [ "$?" != "0" ]; then - _err "FreeDNS retrieve subdomins failed bad RC from _get" - return 1 - elif [ -z "$htmlpage" ]; then - _err "FreeDNS returned empty subdomain page" - return 1 - fi - - _debug2 "$htmlpage" - - printf "%s" "$htmlpage" - return 0 -} - -# usage _freedns_add_txt_record login_cookies domain_id subdomain value -# returns 0 success -_freedns_add_txt_record() { - export _H1="Cookie:$1" - export _H2="Accept-Language:en-US" - domain_id="$2" - subdomain="$3" - value="$(printf '%s' "$4" | _url_encode)" - url="http://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")" - - if [ "$?" != "0" ]; then - _err "FreeDNS failed to add TXT record for $subdomain bad RC from _post" - return 1 - elif ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then - _debug "$htmlpage" - _err "FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file" - return 1 - elif _contains "$htmlpage" "security code was incorrect"; then - _debug "$htmlpage" - _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested seurity code" - _err "Note that you cannot use automatic DNS validation for FreeDNS public domains" - return 1 - fi - - _debug2 "$htmlpage" - _info "Added acme challenge TXT record for $fulldomain at FreeDNS" - return 0 -} - -# usage _freedns_delete_txt_record login_cookies data_id -# returns 0 success -_freedns_delete_txt_record() { - export _H1="Cookie:$1" - export _H2="Accept-Language:en-US" - data_id="$2" - url="https://freedns.afraid.org/subdomain/delete2.php" - - htmlheader="$(_get "$url?data_id%5B%5D=$data_id&submit=delete+selected" "onlyheader")" - - if [ "$?" != "0" ]; then - _err "FreeDNS failed to delete TXT record for $data_id bad RC from _get" - return 1 - elif ! _contains "$htmlheader" "200 OK"; then - _debug "$htmlheader" - _err "FreeDNS failed to delete TXT record $data_id" - return 1 - fi - - _info "Deleted acme challenge TXT record for $fulldomain at FreeDNS" - return 0 -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_gandi_livedns.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_gandi_livedns.sh deleted file mode 100755 index 41f42980b..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_gandi_livedns.sh +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env sh - -# Gandi LiveDNS v5 API -# http://doc.livedns.gandi.net/ -# currently under beta -# -# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable -# -#Author: Frédéric Crozat -#Report Bugs here: https://github.com/fcrozat/acme.sh -# -######## Public functions ##################### - -GANDI_LIVEDNS_API="https://dns.beta.gandi.net/api/v5" - -#Usage: dns_gandi_livedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_gandi_livedns_add() { - fulldomain=$1 - txtvalue=$2 - - if [ -z "$GANDI_LIVEDNS_KEY" ]; then - _err "No API key specifed for Gandi LiveDNS." - _err "Create your key and export it as GANDI_LIVEDNS_KEY" - return 1 - fi - - _saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY" - - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - _err "invalid domain" - return 1 - fi - _debug fulldomain "$fulldomain" - _debug txtvalue "$txtvalue" - _debug domain "$_domain" - _debug sub_domain "$_sub_domain" - - _gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \ - && _contains "$response" '{"message": "Zone Record Created"}' \ - && _info "Add $(__green "success")" -} - -#Usage: fulldomain txtvalue -#Remove the txt record after validation. -dns_gandi_livedns_rm() { - fulldomain=$1 - txtvalue=$2 - - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - _err "invalid domain" - return 1 - fi - - _debug fulldomain "$fulldomain" - _debug domain "$_domain" - _debug sub_domain "$_sub_domain" - - _gandi_livedns_rest DELETE "domains/$_domain/records/$_sub_domain/TXT" "" - -} - -#################### Private functions below ################################## -#_acme-challenge.www.domain.com -#returns -# _sub_domain=_acme-challenge.www -# _domain=domain.com -_get_root() { - domain=$1 - 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 ! _gandi_livedns_rest GET "domains/$h"; then - return 1 - fi - - if _contains "$response" '"code": 401'; then - _err "$response" - return 1 - elif _contains "$response" '"code": 404'; then - _debug "$h not found" - else - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - _domain="$h" - return 0 - fi - p="$i" - i=$(_math "$i" + 1) - done - return 1 -} - -_gandi_livedns_rest() { - m=$1 - ep="$2" - data="$3" - _debug "$ep" - - export _H1="Content-Type: application/json" - export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY" - - if [ "$m" = "GET" ]; then - response="$(_get "$GANDI_LIVEDNS_API/$ep")" - else - _debug data "$data" - response="$(_post "$data" "$GANDI_LIVEDNS_API/$ep" "" "$m")" - fi - - if [ "$?" != "0" ]; then - _err "error $ep" - return 1 - fi - _debug2 response "$response" - return 0 -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_gd.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_gd.sh deleted file mode 100755 index f2dd1fd5a..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_gd.sh +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env sh - -#Godaddy domain api -# -#GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" -# -#GD_Secret="asdfsdfsfsdfsdfdfsdf" - -GD_Api="https://api.godaddy.com/v1" - -######## Public functions ##################### - -#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_gd_add() { - fulldomain=$1 - txtvalue=$2 - - if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then - GD_Key="" - GD_Secret="" - _err "You don't specify godaddy api key and secret yet." - _err "Please create you key and try again." - return 1 - fi - - #save the api key and email to the account conf file. - _saveaccountconf GD_Key "$GD_Key" - _saveaccountconf GD_Secret "$GD_Secret" - - _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" - - _info "Adding record" - if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[{\"data\":\"$txtvalue\"}]"; then - if [ "$response" = "{}" ]; then - _info "Added, sleeping 10 seconds" - _sleep 10 - #todo: check if the record takes effect - return 0 - else - _err "Add txt record error." - _err "$response" - return 1 - fi - fi - _err "Add txt record error." - -} - -#fulldomain -dns_gd_rm() { - fulldomain=$1 - -} - -#################### Private functions below ################################## -#_acme-challenge.www.domain.com -#returns -# _sub_domain=_acme-challenge.www -# _domain=domain.com -_get_root() { - domain=$1 - i=2 - p=1 - while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) - if [ -z "$h" ]; then - #not valid - return 1 - fi - - if ! _gd_rest GET "domains/$h"; then - return 1 - fi - - if _contains "$response" '"code":"NOT_FOUND"'; then - _debug "$h not found" - else - _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) - _domain="$h" - return 0 - fi - p="$i" - i=$(_math "$i" + 1) - done - return 1 -} - -_gd_rest() { - m=$1 - ep="$2" - data="$3" - _debug "$ep" - - export _H1="Authorization: sso-key $GD_Key:$GD_Secret" - export _H2="Content-Type: application/json" - - if [ "$data" ]; then - _debug data "$data" - response="$(_post "$data" "$GD_Api/$ep" "" "$m")" - else - response="$(_get "$GD_Api/$ep")" - fi - - if [ "$?" != "0" ]; then - _err "error $ep" - return 1 - fi - _debug2 response "$response" - return 0 -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_ispconfig.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_ispconfig.sh deleted file mode 100755 index 6d1f34c59..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_ispconfig.sh +++ /dev/null @@ -1,177 +0,0 @@ -#!/usr/bin/env sh - -# ISPConfig 3.1 API -# User must provide login data and URL to the ISPConfig installation incl. port. The remote user in ISPConfig must have access to: -# - DNS zone Functions -# - DNS txt Functions - -# Report bugs to https://github.com/sjau/acme.sh - -# Values to export: -# export ISPC_User="remoteUser" -# export ISPC_Password="remotePassword" -# export ISPC_Api="https://ispc.domain.tld:8080/remote/json.php" -# export ISPC_Api_Insecure=1 # Set 1 for insecure and 0 for secure -> difference is whether ssl cert is checked for validity (0) or whether it is just accepted (1) - -######## Public functions ##################### - -#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_ispconfig_add() { - fulldomain="${1}" - txtvalue="${2}" - _debug "Calling: dns_ispconfig_add() '${fulldomain}' '${txtvalue}'" - _ISPC_credentials && _ISPC_login && _ISPC_getZoneInfo && _ISPC_addTxt -} - -#Usage: dns_myapi_rm _acme-challenge.www.domain.com -dns_ispconfig_rm() { - fulldomain="${1}" - _debug "Calling: dns_ispconfig_rm() '${fulldomain}'" - _ISPC_credentials && _ISPC_login && _ISPC_rmTxt -} - -#################### Private functions below ################################## - -_ISPC_credentials() { - if [ -z "${ISPC_User}" ] || [ -z "$ISPC_Password" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then - ISPC_User="" - ISPC_Password="" - ISPC_Api="" - ISPC_Api_Insecure="" - _err "You haven't specified the ISPConfig Login data, URL and whether you want check the ISPC SSL cert. Please try again." - return 1 - else - _saveaccountconf ISPC_User "${ISPC_User}" - _saveaccountconf ISPC_Password "${ISPC_Password}" - _saveaccountconf ISPC_Api "${ISPC_Api}" - _saveaccountconf ISPC_Api_Insecure "${ISPC_Api_Insecure}" - # Set whether curl should use secure or insecure mode - export HTTPS_INSECURE="${ISPC_Api_Insecure}" - fi -} - -_ISPC_login() { - _info "Getting Session ID" - curData="{\"username\":\"${ISPC_User}\",\"password\":\"${ISPC_Password}\",\"client_login\":false}" - curResult="$(_post "${curData}" "${ISPC_Api}?login")" - _debug "Calling _ISPC_login: '${curData}' '${ISPC_Api}?login'" - _debug "Result of _ISPC_login: '$curResult'" - if _contains "${curResult}" '"code":"ok"'; then - sessionID=$(echo "${curResult}" | _egrep_o "response.*" | cut -d ':' -f 2 | cut -d '"' -f 2) - _info "Retrieved Session ID." - _debug "Session ID: '${sessionID}'" - else - _err "Couldn't retrieve the Session ID." - return 1 - fi -} - -_ISPC_getZoneInfo() { - _info "Getting Zoneinfo" - zoneEnd=false - curZone="${fulldomain}" - while [ "${zoneEnd}" = false ]; do - # we can strip the first part of the fulldomain, since it's just the _acme-challenge string - curZone="${curZone#*.}" - # suffix . needed for zone -> domain.tld. - curData="{\"session_id\":\"${sessionID}\",\"primary_id\":{\"origin\":\"${curZone}.\"}}" - curResult="$(_post "${curData}" "${ISPC_Api}?dns_zone_get")" - _debug "Calling _ISPC_getZoneInfo: '${curData}' '${ISPC_Api}?login'" - _debug "Result of _ISPC_getZoneInfo: '$curResult'" - if _contains "${curResult}" '"id":"'; then - zoneFound=true - zoneEnd=true - _info "Retrieved zone data." - _debug "Zone data: '${curResult}'" - fi - if [ "${curZone#*.}" != "$curZone" ]; then - _debug2 "$curZone still contains a '.' - so we can check next higher level" - else - zoneEnd=true - _err "Couldn't retrieve zone data." - return 1 - fi - done - if [ "${zoneFound}" ]; then - server_id=$(echo "${curResult}" | _egrep_o "server_id.*" | cut -d ':' -f 2 | cut -d '"' -f 2) - _debug "Server ID: '${server_id}'" - case "${server_id}" in - '' | *[!0-9]*) - _err "Server ID is not numeric." - return 1 - ;; - *) _info "Retrieved Server ID" ;; - esac - zone=$(echo "${curResult}" | _egrep_o "\"id.*" | cut -d ':' -f 2 | cut -d '"' -f 2) - _debug "Zone: '${zone}'" - case "${zone}" in - '' | *[!0-9]*) - _err "Zone ID is not numeric." - return 1 - ;; - *) _info "Retrieved Zone ID" ;; - esac - client_id=$(echo "${curResult}" | _egrep_o "sys_userid.*" | cut -d ':' -f 2 | cut -d '"' -f 2) - _debug "Client ID: '${client_id}'" - case "${client_id}" in - '' | *[!0-9]*) - _err "Client ID is not numeric." - return 1 - ;; - *) _info "Retrieved Client ID." ;; - esac - zoneFound="" - zoneEnd="" - fi -} - -_ISPC_addTxt() { - curSerial="$(date +%s)" - curStamp="$(date +'%F %T')" - params="\"server_id\":\"${server_id}\",\"zone\":\"${zone}\",\"name\":\"${fulldomain}.\",\"type\":\"txt\",\"data\":\"${txtvalue}\",\"aux\":\"0\",\"ttl\":\"3600\",\"active\":\"y\",\"stamp\":\"${curStamp}\",\"serial\":\"${curSerial}\"" - curData="{\"session_id\":\"${sessionID}\",\"client_id\":\"${client_id}\",\"params\":{${params}}}" - curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_add")" - _debug "Calling _ISPC_addTxt: '${curData}' '${ISPC_Api}?dns_txt_add'" - _debug "Result of _ISPC_addTxt: '$curResult'" - record_id=$(echo "${curResult}" | _egrep_o "\"response.*" | cut -d ':' -f 2 | cut -d '"' -f 2) - _debug "Record ID: '${record_id}'" - case "${record_id}" in - '' | *[!0-9]*) - _err "Couldn't add ACME Challenge TXT record to zone." - return 1 - ;; - *) _info "Added ACME Challenge TXT record to zone." ;; - esac -} - -_ISPC_rmTxt() { - # Need to get the record ID. - curData="{\"session_id\":\"${sessionID}\",\"primary_id\":{\"name\":\"${fulldomain}.\",\"type\":\"TXT\"}}" - curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_get")" - _debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_get'" - _debug "Result of _ISPC_rmTxt: '$curResult'" - if _contains "${curResult}" '"code":"ok"'; then - record_id=$(echo "${curResult}" | _egrep_o "\"id.*" | cut -d ':' -f 2 | cut -d '"' -f 2) - _debug "Record ID: '${record_id}'" - case "${record_id}" in - '' | *[!0-9]*) - _err "Record ID is not numeric." - return 1 - ;; - *) - unset IFS - _info "Retrieved Record ID." - curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\"}" - curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_delete")" - _debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_delete'" - _debug "Result of _ISPC_rmTxt: '$curResult'" - if _contains "${curResult}" '"code":"ok"'; then - _info "Removed ACME Challenge TXT record from zone." - else - _err "Couldn't remove ACME Challenge TXT record from zone." - return 1 - fi - ;; - esac - fi -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_lexicon.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_lexicon.sh deleted file mode 100755 index c09f16fd6..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_lexicon.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env sh - -# dns api wrapper of lexicon for acme.sh - -# https://github.com/AnalogJ/lexicon -lexicon_cmd="lexicon" - -wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api" - -######## Public functions ##################### - -#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_lexicon_add() { - fulldomain=$1 - txtvalue=$2 - - domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999) - - if ! _exists "$lexicon_cmd"; then - _err "Please install $lexicon_cmd first: $wiki" - return 1 - fi - - if [ -z "$PROVIDER" ]; then - PROVIDER="" - _err "Please define env PROVIDER first: $wiki" - return 1 - fi - - _savedomainconf PROVIDER "$PROVIDER" - export PROVIDER - - # e.g. busybox-ash does not know [:upper:] - # shellcheck disable=SC2018,SC2019 - Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z') - Lx_name_v=$(eval echo \$"$Lx_name") - _secure_debug "$Lx_name" "$Lx_name_v" - if [ "$Lx_name_v" ]; then - _saveaccountconf "$Lx_name" "$Lx_name_v" - eval export "$Lx_name" - fi - - # shellcheck disable=SC2018,SC2019 - Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z') - Lx_token_v=$(eval echo \$"$Lx_token") - _secure_debug "$Lx_token" "$Lx_token_v" - if [ "$Lx_token_v" ]; then - _saveaccountconf "$Lx_token" "$Lx_token_v" - eval export "$Lx_token" - fi - - # shellcheck disable=SC2018,SC2019 - Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z') - Lx_password_v=$(eval echo \$"$Lx_password") - _secure_debug "$Lx_password" "$Lx_password_v" - if [ "$Lx_password_v" ]; then - _saveaccountconf "$Lx_password" "$Lx_password_v" - eval export "$Lx_password" - fi - - # shellcheck disable=SC2018,SC2019 - Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z') - Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken") - _secure_debug "$Lx_domaintoken" "$Lx_domaintoken_v" - if [ "$Lx_domaintoken_v" ]; then - eval export "$Lx_domaintoken" - _saveaccountconf "$Lx_domaintoken" "$Lx_domaintoken_v" - fi - - $lexicon_cmd "$PROVIDER" create "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" - -} - -#fulldomain -dns_lexicon_rm() { - fulldomain=$1 - -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_linode.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_linode.sh deleted file mode 100755 index 6d54e6c12..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_linode.sh +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env sh - -#Author: Philipp Grosswiler - -LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action=" - -######## Public functions ##################### - -#Usage: dns_linode_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_linode_add() { - fulldomain="${1}" - txtvalue="${2}" - - if ! _Linode_API; then - return 1 - fi - - _info "Using Linode" - _debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'" - - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - _err "Domain does not exist." - return 1 - fi - _debug _domain_id "$_domain_id" - _debug _sub_domain "$_sub_domain" - _debug _domain "$_domain" - - _parameters="&DomainID=$_domain_id&Type=TXT&Name=$_sub_domain&Target=$txtvalue" - - if _rest GET "domain.resource.create" "$_parameters" && [ -n "$response" ]; then - _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) - _debug _resource_id "$_resource_id" - - if [ -z "$_resource_id" ]; then - _err "Error adding the domain resource." - return 1 - fi - - _info "Domain resource successfully added." - return 0 - fi - - return 1 -} - -#Usage: dns_linode_rm _acme-challenge.www.domain.com -dns_linode_rm() { - fulldomain="${1}" - - if ! _Linode_API; then - return 1 - fi - - _info "Using Linode" - _debug "Calling: dns_linode_rm() '${fulldomain}'" - - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - _err "Domain does not exist." - return 1 - fi - _debug _domain_id "$_domain_id" - _debug _sub_domain "$_sub_domain" - _debug _domain "$_domain" - - _parameters="&DomainID=$_domain_id" - - if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then - response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" - - resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" - if [ "$resource" ]; then - _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"RESOURCEID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) - if [ "$_resource_id" ]; then - _debug _resource_id "$_resource_id" - - _parameters="&DomainID=$_domain_id&ResourceID=$_resource_id" - - if _rest GET "domain.resource.delete" "$_parameters" && [ -n "$response" ]; then - _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) - _debug _resource_id "$_resource_id" - - if [ -z "$_resource_id" ]; then - _err "Error deleting the domain resource." - return 1 - fi - - _info "Domain resource successfully deleted." - return 0 - fi - fi - - return 1 - fi - - return 0 - fi - - return 1 -} - -#################### Private functions below ################################## - -_Linode_API() { - if [ -z "$LINODE_API_KEY" ]; then - LINODE_API_KEY="" - - _err "You didn't specify the Linode API key yet." - _err "Please create your key and try again." - - return 1 - fi - - _saveaccountconf LINODE_API_KEY "$LINODE_API_KEY" -} - -#################### 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 _rest GET "domain.list"; 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 "{.*\"DOMAIN\":\s*\"$h\".*}")" - if [ "$hostedzone" ]; then - _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"DOMAINID\":\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 method action data -_rest() { - mtd="$1" - ep="$2" - data="$3" - - _debug mtd "$mtd" - _debug ep "$ep" - - export _H1="Accept: application/json" - export _H2="Content-Type: application/json" - - if [ "$mtd" != "GET" ]; then - # both POST and DELETE. - _debug data "$data" - response="$(_post "$data" "$LINODE_API_URL$ep" "" "$mtd")" - else - response="$(_get "$LINODE_API_URL$ep$data")" - fi - - if [ "$?" != "0" ]; then - _err "error $ep" - return 1 - fi - _debug2 response "$response" - return 0 -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_lua.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_lua.sh deleted file mode 100755 index 00c544307..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_lua.sh +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/env sh - -# bug reports to dev@1e.ca - -# -#LUA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" -# -#LUA_Email="user@luadns.net" - -LUA_Api="https://api.luadns.com/v1" -LUA_auth=$(printf "%s" "$LUA_Email:$LUA_Key" | _base64) - -######## Public functions ##################### - -#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_lua_add() { - fulldomain=$1 - txtvalue=$2 - - if [ -z "$LUA_Key" ] || [ -z "$LUA_Email" ]; then - LUA_Key="" - LUA_Email="" - _err "You don't specify luadns api key and email yet." - _err "Please create you key and try again." - return 1 - fi - - #save the api key and email to the account conf file. - _saveaccountconf LUA_Key "$LUA_Key" - _saveaccountconf LUA_Email "$LUA_Email" - - _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" - _LUA_rest GET "zones/${_domain_id}/records" - - if ! _contains "$response" "\"id\":"; then - _err "Error" - return 1 - fi - - count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ") - _debug count "$count" - if [ "$count" = "0" ]; then - _info "Adding record" - if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then - if _contains "$response" "$fulldomain"; then - _info "Added" - #todo: check if the record takes effect - return 0 - else - _err "Add txt record error." - return 1 - fi - fi - _err "Add txt record error." - else - _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1) - _debug "record_id" "$record_id" - - _LUA_rest PUT "zones/$_domain_id/records/$record_id" "{\"id\":$record_id,\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"zone_id\":$_domain_id,\"ttl\":120}" - if [ "$?" = "0" ] && _contains "$response" "updated_at"; then - _info "Updated!" - #todo: check if the record takes effect - return 0 - fi - _err "Update error" - return 1 - fi - -} - -#fulldomain -dns_lua_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" - _LUA_rest GET "zones/${_domain_id}/records" - - count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ") - _debug count "$count" - if [ "$count" = "0" ]; then - _info "Don't need to remove." - else - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1) - _debug "record_id" "$record_id" - if [ -z "$record_id" ]; then - _err "Can not get record id to remove." - return 1 - fi - if ! _LUA_rest DELETE "/zones/$_domain_id/records/$record_id"; then - _err "Delete record error." - return 1 - fi - _contains "$response" "$record_id" - fi -} - -#################### Private functions below ################################## -#_acme-challenge.www.domain.com -#returns -# _sub_domain=_acme-challenge.www -# _domain=domain.com -# _domain_id=sdjkglgdfewsdfg -_get_root() { - domain=$1 - i=2 - p=1 - if ! _LUA_rest GET "zones"; then - return 1 - fi - 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" "\"name\":\"$h\""; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$h\"" | cut -d : -f 2 | cut -d , -f 1) - _debug _domain_id "$_domain_id" - 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 - return 1 -} - -_LUA_rest() { - m=$1 - ep="$2" - data="$3" - _debug "$ep" - - export _H1="Accept: application/json" - export _H2="Authorization: Basic $LUA_auth" - if [ "$m" != "GET" ]; then - _debug data "$data" - response="$(_post "$data" "$LUA_Api/$ep" "" "$m")" - else - response="$(_get "$LUA_Api/$ep")" - fi - - if [ "$?" != "0" ]; then - _err "error $ep" - return 1 - fi - _debug2 response "$response" - return 0 -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_me.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_me.sh deleted file mode 100755 index 03c2b758b..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_me.sh +++ /dev/null @@ -1,175 +0,0 @@ -#!/usr/bin/env sh - -# bug reports to dev@1e.ca - -# ME_Key=qmlkdjflmkqdjf -# ME_Secret=qmsdlkqmlksdvnnpae - -ME_Api=https://api.dnsmadeeasy.com/V2.0/dns/managed - -######## Public functions ##################### - -#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_me_add() { - fulldomain=$1 - txtvalue=$2 - - if [ -z "$ME_Key" ] || [ -z "$ME_Secret" ]; then - ME_Key="" - ME_Secret="" - _err "You didn't specify DNSMadeEasy api key and secret yet." - _err "Please create you key and try again." - return 1 - fi - - #save the api key and email to the account conf file. - _saveaccountconf ME_Key "$ME_Key" - _saveaccountconf ME_Secret "$ME_Secret" - - _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" - _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" - - if ! _contains "$response" "\"totalRecords\":"; then - _err "Error" - return 1 - fi - - count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2) - _debug count "$count" - if [ "$count" = "0" ]; then - _info "Adding record" - if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then - if printf -- "%s" "$response" | grep \"id\": >/dev/null; then - _info "Added" - #todo: check if the record takes effect - return 0 - else - _err "Add txt record error." - return 1 - fi - fi - _err "Add txt record error." - else - _info "Updating record" - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | head -n 1) - _debug "record_id" "$record_id" - - _me_rest PUT "$_domain_id/records/$record_id/" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}" - if [ "$?" = "0" ]; then - _info "Updated" - #todo: check if the record takes effect - return 0 - fi - _err "Update error" - return 1 - fi - -} - -#fulldomain -dns_me_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" - _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" - - count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2) - _debug count "$count" - if [ "$count" = "0" ]; then - _info "Don't need to remove." - else - record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | head -n 1) - _debug "record_id" "$record_id" - if [ -z "$record_id" ]; then - _err "Can not get record id to remove." - return 1 - fi - if ! _me_rest DELETE "$_domain_id/records/$record_id"; then - _err "Delete record error." - return 1 - fi - _contains "$response" '' - fi -} - -#################### Private functions below ################################## -#_acme-challenge.www.domain.com -#returns -# _sub_domain=_acme-challenge.www -# _domain=domain.com -# _domain_id=sdjkglgdfewsdfg -_get_root() { - domain=$1 - i=2 - p=1 - while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) - if [ -z "$h" ]; then - #not valid - return 1 - fi - - if ! _me_rest GET "name?domainname=$h"; then - return 1 - fi - - if _contains "$response" "\"name\":\"$h\""; then - _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | 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 - return 1 -} - -_me_rest() { - m=$1 - ep="$2" - data="$3" - _debug "$ep" - - cdate=$(date -u +"%a, %d %b %Y %T %Z") - hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(printf "%s" "$ME_Secret" | _hex_dump | tr -d " ")" hex) - - export _H1="x-dnsme-apiKey: $ME_Key" - export _H2="x-dnsme-requestDate: $cdate" - export _H3="x-dnsme-hmac: $hmac" - - if [ "$m" != "GET" ]; then - _debug data "$data" - response="$(_post "$data" "$ME_Api/$ep" "" "$m")" - else - response="$(_get "$ME_Api/$ep")" - fi - - if [ "$?" != "0" ]; then - _err "error $ep" - return 1 - fi - _debug2 response "$response" - return 0 -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_myapi.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_myapi.sh deleted file mode 100755 index 6bf625081..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_myapi.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env sh - -#Here is a sample custom api script. -#This file name is "dns_myapi.sh" -#So, here must be a method dns_myapi_add() -#Which will be called by acme.sh to add the txt record to your api system. -#returns 0 means success, otherwise error. -# -#Author: Neilpang -#Report Bugs here: https://github.com/Neilpang/acme.sh -# -######## Public functions ##################### - -#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_myapi_add() { - fulldomain=$1 - txtvalue=$2 - _info "Using myapi" - _debug fulldomain "$fulldomain" - _debug txtvalue "$txtvalue" - _err "Not implemented!" - return 1 -} - -#Usage: fulldomain txtvalue -#Remove the txt record after validation. -dns_myapi_rm() { - fulldomain=$1 - txtvalue=$2 - _info "Using myapi" - _debug fulldomain "$fulldomain" - _debug txtvalue "$txtvalue" -} - -#################### Private functions below ################################## diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_nsupdate.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_nsupdate.sh deleted file mode 100755 index 7acb2ef77..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_nsupdate.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env sh - -######## Public functions ##################### - -#Usage: dns_nsupdate_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_nsupdate_add() { - fulldomain=$1 - txtvalue=$2 - _checkKeyFile || return 1 - [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" - # save the dns server and key to the account conf file. - _saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}" - _saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}" - _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" - nsupdate -k "${NSUPDATE_KEY}" </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 -} - -_ovh_timestamp() { - _H1="" - _H2="" - _H3="" - _H4="" - _H5="" - _get "$OVH_API/auth/time" "" 30 -} - -_ovh_rest() { - m=$1 - ep="$2" - data="$3" - _debug "$ep" - - _ovh_url="$OVH_API/$ep" - _debug2 _ovh_url "$_ovh_url" - _ovh_t="$(_ovh_timestamp)" - _debug2 _ovh_t "$_ovh_t" - _ovh_p="$OVH_AS+$OVH_CK+$m+$_ovh_url+$data+$_ovh_t" - _secure_debug _ovh_p "$_ovh_p" - _ovh_hex="$(printf "%s" "$_ovh_p" | _digest sha1 hex)" - _debug2 _ovh_hex "$_ovh_hex" - - export _H1="X-Ovh-Application: $OVH_AK" - export _H2="X-Ovh-Signature: \$1\$$_ovh_hex" - _debug2 _H2 "$_H2" - export _H3="X-Ovh-Timestamp: $_ovh_t" - export _H4="X-Ovh-Consumer: $OVH_CK" - export _H5="Content-Type: application/json;charset=utf-8" - if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ]; then - _debug data "$data" - response="$(_post "$data" "$_ovh_url" "" "$m")" - else - response="$(_get "$_ovh_url")" - fi - - if [ "$?" != "0" ]; then - _err "error $ep" - return 1 - fi - _debug2 response "$response" - return 0 -} diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_pdns.sh b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_pdns.sh deleted file mode 100755 index ebc029490..000000000 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/dnsapi/dns_pdns.sh +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/bin/env sh - -#PowerDNS Emdedded API -#https://doc.powerdns.com/md/httpapi/api_spec/ -# -#PDNS_Url="http://ns.example.com:8081" -#PDNS_ServerId="localhost" -#PDNS_Token="0123456789ABCDEF" -#PDNS_Ttl=60 - -DEFAULT_PDNS_TTL=60 - -######## Public functions ##################### -#Usage: add _acme-challenge.www.domain.com "123456789ABCDEF0000000000000000000000000000000000000" -#fulldomain -#txtvalue -dns_pdns_add() { - fulldomain=$1 - txtvalue=$2 - - if [ -z "$PDNS_Url" ]; then - PDNS_Url="" - _err "You don't specify PowerDNS address." - _err "Please set PDNS_Url and try again." - return 1 - fi - - if [ -z "$PDNS_ServerId" ]; then - PDNS_ServerId="" - _err "You don't specify PowerDNS server id." - _err "Please set you PDNS_ServerId and try again." - return 1 - fi - - if [ -z "$PDNS_Token" ]; then - PDNS_Token="" - _err "You don't specify PowerDNS token." - _err "Please create you PDNS_Token and try again." - return 1 - fi - - if [ -z "$PDNS_Ttl" ]; then - PDNS_Ttl="$DEFAULT_PDNS_TTL" - fi - - #save the api addr and key to the account conf file. - _saveaccountconf PDNS_Url "$PDNS_Url" - _saveaccountconf PDNS_ServerId "$PDNS_ServerId" - _saveaccountconf PDNS_Token "$PDNS_Token" - - if [ "$PDNS_Ttl" != "$DEFAULT_PDNS_TTL" ]; then - _saveaccountconf PDNS_Ttl "$PDNS_Ttl" - fi - - _debug "Detect root zone" - if ! _get_root "$fulldomain"; then - _err "invalid domain" - return 1 - fi - _debug _domain "$_domain" - - if ! set_record "$_domain" "$fulldomain" "$txtvalue"; then - return 1 - fi - - return 0 -} - -#fulldomain -dns_pdns_rm() { - fulldomain=$1 - - _debug "Detect root zone" - if ! _get_root "$fulldomain"; then - _err "invalid domain" - return 1 - fi - _debug _domain "$_domain" - - if ! rm_record "$_domain" "$fulldomain"; then - return 1 - fi - - return 0 -} - -set_record() { - _info "Adding record" - root=$1 - full=$2 - 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 - _err "Set txt record error." - return 1 - fi - - if ! notify_slaves "$root"; then - return 1 - fi - - return 0 -} - -rm_record() { - _info "Remove record" - root=$1 - full=$2 - - if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root." "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then - _err "Delete txt record error." - return 1 - fi - - if ! notify_slaves "$root"; then - return 1 - fi - - return 0 -} - -notify_slaves() { - root=$1 - - if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root./notify"; then - _err "Notify slaves error." - return 1 - fi - - return 0 -} - -#################### Private functions below ################################## -#_acme-challenge.www.domain.com -#returns -# _domain=domain.com -_get_root() { - domain=$1 - i=1 - - if _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones"; then - _zones_response="$response" - fi - - while true; do - h=$(printf "%s" "$domain" | cut -d . -f $i-100) - if [ -z "$h" ]; then - return 1 - fi - - if _contains "$_zones_response" "\"name\": \"$h.\""; then - _domain="$h" - return 0 - fi - - i=$(_math $i + 1) - done - _debug "$domain not found" - - return 1 -} - -_pdns_rest() { - method=$1 - ep=$2 - data=$3 - - export _H1="X-API-Key: $PDNS_Token" - - if [ ! "$method" = "GET" ]; then - _debug data "$data" - response="$(_post "$data" "$PDNS_Url$ep" "" "$method")" - else - response="$(_get "$PDNS_Url$ep")" - fi - - if [ "$?" != "0" ]; then - _err "error $ep" - return 1 - fi - _debug2 response "$response" - - return 0 -}