From bcf63b5d270a4535347e64e7f25f24970e474e6f Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Sun, 27 Feb 2022 14:17:34 +0100 Subject: [PATCH 01/55] Add ArtFiles.de DNS API plugin --- dnsapi/dns_artfiles.sh | 176 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 dnsapi/dns_artfiles.sh diff --git a/dnsapi/dns_artfiles.sh b/dnsapi/dns_artfiles.sh new file mode 100644 index 00000000..c857060a --- /dev/null +++ b/dnsapi/dns_artfiles.sh @@ -0,0 +1,176 @@ +#!/usr/bin/env sh + +################################################################################ +# ACME.sh 3rd party DNS API plugin for ArtFiles.de +################################################################################ +# Author: Martin Arndt, https://troublezone.net/ +# Released: 2022-02-27 +# Issues: https://github.com/acmesh-official/acme.sh/issues/XXXX +################################################################################ +# Usage: +# 1. export AF_API_Username="api12345678" +# 2. export AF_API_Password="apiPassword" +# 3. acme.sh --issue -d example.com --dns dns_artfiles +################################################################################ + +########## API configuration ################################################### +AF_API_SUCCESS='status":"OK' +AF_URL_DCP='https://dcp.c.artfiles.de/api/' +AF_URL_DNS=${AF_URL_DCP}'dns/{*}_dns.html?domain=' +AF_URL_DOMAINS=${AF_URL_BASE}'domain/get_domains.html' + +########## Public functions #################################################### + +# Adds a new TXT record for given ACME challenge value & domain. +# Usage: dns_artfiles_add _acme-challenge.www.example.com "ACME challenge value" +dns_artfiles_add() { + domain="$1" + txtValue="$2" + _info 'Using ArtFiles.de DNS addition API' + _debug 'Domain' "$domain" + _debug 'txtValue' "$txtValue" + + AF_API_USERNAME="${AF_API_USERNAME:-$(_readaccountconf_mutable AF_API_USERNAME)}" + AF_API_PASSWORD="${AF_API_PASSWORD:-$(_readaccountconf_mutable AF_API_PASSWORD)}" + if [ -z "$AF_API_USERNAME" ] || [ -z "$AF_API_PASSWORD" ]; then + _err 'Missing ArtFiles.de username and/or password.' + _err 'Please ensure both are set via export command & try again.' + + return 1 + fi + + _saveaccountconf_mutable 'AF_API_USERNAME' "$AF_API_USERNAME" + _saveaccountconf_mutable 'AF_API_PASSWORD' "$AF_API_PASSWORD" + + _set_headers + _get_zone "$domain" + _dns 'GET' + if ! _contains "$response" 'TXT'; then + _err 'Retrieving TXT records failed.' + + return 1 + fi + + _clean_records + _dns 'SET' "$(printf -- '%s\n_acme-challenge "%s"' "$response" "$txtValue")" + if ! _contains "$response" "$AF_API_SUCCESS"; then + _err 'Adding ACME challenge value failed.' + + return 1 + fi +} + +# Removes the existing TXT record for given ACME challenge value & domain. +# Usage: dns_artfiles_rm _acme-challenge.www.example.com "ACME challenge value" +dns_artfiles_rm() { + domain="$1" + txtValue="$2" + _info 'Using ArtFiles.de DNS removal API' + _debug 'Domain' "$domain" + _debug 'txtValue' "$txtValue" + + _set_headers + _get_zone "$domain" + if ! _dns 'GET'; then + return 1 + fi + + if ! _contains "$response" "$txtValue"; then + _err 'Retrieved TXT records are missing given ACME challenge value.' + + return 1 + fi + + _clean_records + response="$(printf -- '%s' "$response" | sed '$d')" + _dns 'SET' "$response" + if ! _contains "$response" "$AF_API_SUCCESS"; then + _err 'Removing ACME challenge value failed.' + + return 1 + fi +} + +########## Private functions ################################################### + +# Cleans awful TXT records response of ArtFiles's API & pretty prints it. +# Usage: _clean_records +_clean_records() +{ + # Extract TXT part, strip trailing quote sign (ACME.sh API guidelines forbid + # usage of SED's GNU extensions, hence couldn't omit it via regex), strip '\' + # from '\"' & turn '\n' into real LF characters. + # Yup, awful API to use - but that's all we got to get this working, so... ;) + _debug2 'Raw ' "$response" + response="$(printf -- '%s' "$response" + \ | sed 's/^\(.*TXT":"\)\([^,}]*\)\(.*\)$/\2/;s/.$//;s/\\"/"/g;s/\\n/\n/g')" + _debug2 'Clean' "$response" +} + +# Executes an HTTP GET or POST request for getting or setting DNS records, +# containing given payload upon POST. +# Usage: _dns [GET | SET] [payload] +_dns() +{ + action="$1" + payload="$(printf -- '%s' "$2" | _url_encode)" + url="$(printf -- '%s%s' "$AF_URL_DNS" "$domain" + \ | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/')" + + if [ "$action" = 'SET' ]; then + _debug2 'Payload' "$payload" + response="$(_post '' "$url&TXT=$payload" '' 'POST' 'application/x-www-form-urlencoded')" + else + response="$(_get "$url" '' 10)" + fi + + if ! _contains "$response" "$AF_API_SUCCESS"; then + _err "DNS API error: $response" + + return 1 + fi + + _debug 'Response' "$response" + + return 0 +} + +# Gets the root domain zone for given domain. +# Usage: _get_zone _acme-challenge.www.example.com +_get_zone() +{ + _info 'Getting domain zone...' + _debug2 'Initial FQDN' "$1" + fqdn="$1" + fqdn="${fqdn#*.}" # Strip "_acme-challenge" right away + _debug2 'Reduced FQDN' "$fqdn" + + domains="$(_get "$AF_URL_DOMAINS" '' 10)" + while true; do + if _contains "$domains" "$fqdn"; then + domain="$fqdn" + _info "Found root domain zone: $domain" + break + else + fqdn="${fqdn#*.}" + _debug2 'FQDN' "$fqdn" + fi + done + + if [ "$domain" = "$fqdn" ]; then + return 0 + fi + + _err "Couldn't find root domain zone." + + return 1 +} + +# Adds the HTTP Authorization & Content-Type headers to a follow-up request. +# Usage: _set_headers +_set_headers() +{ + encoded="$(printf -- '%s:%s' "$AF_API_USERNAME" "$AF_API_PASSWORD" | _base64)" + export _H1="Authorization: Basic $encoded" + export _H2='Content-Type: application/json' +} From 72d02f442e2e8528afb04a0e55c88185bb99a7e9 Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Sun, 27 Feb 2022 14:35:21 +0100 Subject: [PATCH 02/55] Fix formatting according to Shellcheck --- dnsapi/dns_artfiles.sh | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/dnsapi/dns_artfiles.sh b/dnsapi/dns_artfiles.sh index c857060a..4598854d 100644 --- a/dnsapi/dns_artfiles.sh +++ b/dnsapi/dns_artfiles.sh @@ -95,8 +95,7 @@ dns_artfiles_rm() { # Cleans awful TXT records response of ArtFiles's API & pretty prints it. # Usage: _clean_records -_clean_records() -{ +_clean_records() { # Extract TXT part, strip trailing quote sign (ACME.sh API guidelines forbid # usage of SED's GNU extensions, hence couldn't omit it via regex), strip '\' # from '\"' & turn '\n' into real LF characters. @@ -110,8 +109,7 @@ _clean_records() # Executes an HTTP GET or POST request for getting or setting DNS records, # containing given payload upon POST. # Usage: _dns [GET | SET] [payload] -_dns() -{ +_dns() { action="$1" payload="$(printf -- '%s' "$2" | _url_encode)" url="$(printf -- '%s%s' "$AF_URL_DNS" "$domain" @@ -137,8 +135,7 @@ _dns() # Gets the root domain zone for given domain. # Usage: _get_zone _acme-challenge.www.example.com -_get_zone() -{ +_get_zone() { _info 'Getting domain zone...' _debug2 'Initial FQDN' "$1" fqdn="$1" @@ -168,8 +165,7 @@ _get_zone() # Adds the HTTP Authorization & Content-Type headers to a follow-up request. # Usage: _set_headers -_set_headers() -{ +_set_headers() { encoded="$(printf -- '%s:%s' "$AF_API_USERNAME" "$AF_API_PASSWORD" | _base64)" export _H1="Authorization: Basic $encoded" export _H2='Content-Type: application/json' From 0bea2e2b94e49f59e05c7507bcec548c50a4abac Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Sun, 27 Feb 2022 14:37:22 +0100 Subject: [PATCH 03/55] Fix formatting according to Shellcheck 2/2 --- dnsapi/dns_artfiles.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dnsapi/dns_artfiles.sh b/dnsapi/dns_artfiles.sh index 4598854d..f83ce64a 100644 --- a/dnsapi/dns_artfiles.sh +++ b/dnsapi/dns_artfiles.sh @@ -101,8 +101,9 @@ _clean_records() { # from '\"' & turn '\n' into real LF characters. # Yup, awful API to use - but that's all we got to get this working, so... ;) _debug2 'Raw ' "$response" - response="$(printf -- '%s' "$response" - \ | sed 's/^\(.*TXT":"\)\([^,}]*\)\(.*\)$/\2/;s/.$//;s/\\"/"/g;s/\\n/\n/g')" + response="$( + printf -- '%s' "$response" + \ | sed 's/^\(.*TXT":"\)\([^,}]*\)\(.*\)$/\2/;s/.$//;s/\\"/"/g;s/\\n/\n/g')" _debug2 'Clean' "$response" } @@ -112,8 +113,9 @@ _clean_records() { _dns() { action="$1" payload="$(printf -- '%s' "$2" | _url_encode)" - url="$(printf -- '%s%s' "$AF_URL_DNS" "$domain" - \ | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/')" + url="$( + printf -- '%s%s' "$AF_URL_DNS" "$domain" + \ | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/')" if [ "$action" = 'SET' ]; then _debug2 'Payload' "$payload" From fb457968ecae380bc17914f22d134bcfba93d304 Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Sun, 27 Feb 2022 14:38:24 +0100 Subject: [PATCH 04/55] Fix formatting according to Shellcheck 3/3 --- dnsapi/dns_artfiles.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_artfiles.sh b/dnsapi/dns_artfiles.sh index f83ce64a..9c1a4338 100644 --- a/dnsapi/dns_artfiles.sh +++ b/dnsapi/dns_artfiles.sh @@ -103,7 +103,8 @@ _clean_records() { _debug2 'Raw ' "$response" response="$( printf -- '%s' "$response" - \ | sed 's/^\(.*TXT":"\)\([^,}]*\)\(.*\)$/\2/;s/.$//;s/\\"/"/g;s/\\n/\n/g')" + \ | sed 's/^\(.*TXT":"\)\([^,}]*\)\(.*\)$/\2/;s/.$//;s/\\"/"/g;s/\\n/\n/g' + )" _debug2 'Clean' "$response" } @@ -115,7 +116,8 @@ _dns() { payload="$(printf -- '%s' "$2" | _url_encode)" url="$( printf -- '%s%s' "$AF_URL_DNS" "$domain" - \ | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/')" + \ | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/' + )" if [ "$action" = 'SET' ]; then _debug2 'Payload' "$payload" From ed56d52af309a4d90747169a321dbd3698a4b71a Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Sun, 27 Feb 2022 15:12:05 +0100 Subject: [PATCH 05/55] Changed GitHub issues URL --- dnsapi/dns_artfiles.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_artfiles.sh b/dnsapi/dns_artfiles.sh index 9c1a4338..8e0a6151 100644 --- a/dnsapi/dns_artfiles.sh +++ b/dnsapi/dns_artfiles.sh @@ -5,7 +5,7 @@ ################################################################################ # Author: Martin Arndt, https://troublezone.net/ # Released: 2022-02-27 -# Issues: https://github.com/acmesh-official/acme.sh/issues/XXXX +# Issues: https://github.com/Eagle3386/acme.sh/issues ################################################################################ # Usage: # 1. export AF_API_Username="api12345678" From 13c71829485aac03e1d0da98784ea50e983e73cd Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Sat, 18 Jun 2022 17:32:56 +0200 Subject: [PATCH 06/55] Fix usage docs in file's header comment --- dnsapi/dns_artfiles.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_artfiles.sh b/dnsapi/dns_artfiles.sh index 8e0a6151..2f8e158f 100644 --- a/dnsapi/dns_artfiles.sh +++ b/dnsapi/dns_artfiles.sh @@ -8,8 +8,8 @@ # Issues: https://github.com/Eagle3386/acme.sh/issues ################################################################################ # Usage: -# 1. export AF_API_Username="api12345678" -# 2. export AF_API_Password="apiPassword" +# 1. export AF_API_USERNAME="api12345678" +# 2. export AF_API_PASSWORD="apiPassword" # 3. acme.sh --issue -d example.com --dns dns_artfiles ################################################################################ From cbb7082afd25419779152faf7d35b664a09030b3 Mon Sep 17 00:00:00 2001 From: sg1888 Date: Fri, 31 Mar 2023 00:33:44 +0000 Subject: [PATCH 07/55] Fixed bug with wildcard certs and ecc keys --- deploy/panos.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index ef622ded..3ee889b7 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -61,7 +61,7 @@ deployer() { content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key" content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem" content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"passphrase\"\r\n\r\n123456" - content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_cdomain.key")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" fi #Close multipart content="$content${nl}--$delim--${nl}${nl}" @@ -92,9 +92,18 @@ deployer() { # This is the main function that will call the other functions to deploy everything. panos_deploy() { - _cdomain="$1" + _cdomain=${1//[*]/WILDCARD_} #Wildcard Safe filename _ckey="$2" _cfullchain="$5" + # VALID ECC KEY CHECK + if [[ "${_ckey: -8}" == "_ecc.key" ]] && [[ ! -f $_ckey ]]; then + _debug "The ECC key $_ckey doesn't exist. Attempting to strip _ecc from the filename" + _ckey="${_ckey:0:${#_ckey}-8}.key" + if [[ ! -f $_ckey ]]; then + _err "Still didn't work. Try issuing the certificate using RSA (non-ECC) encryption." + return 1 + fi + fi # PANOS ENV VAR check if [ -z "$PANOS_USER" ] || [ -z "$PANOS_PASS" ] || [ -z "$PANOS_HOST" ]; then _debug "No ENV variables found lets check for saved variables" From df753e2619f5e0069955ed07e32f6a340418126b Mon Sep 17 00:00:00 2001 From: sg1888 Date: Wed, 12 Apr 2023 22:00:53 +0000 Subject: [PATCH 08/55] Added functionality to save and reuse API key --- deploy/panos.sh | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index 3ee889b7..8edf115b 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -25,15 +25,27 @@ parse_response() { else status=$(echo "$1" | sed 's/^.*"\([a-z]*\)".*/\1/g') message=$(echo "$1" | sed 's/^.*\(.*\)<\/result.*/\1/g') + if [ "$type" = 'testkey' ] && [ "$status" != "success" ]; then + _debug "**** Saved API key is invalid ****" + unset _panos_key + fi fi return 0 } deployer() { content="" - type=$1 # Types are keygen, cert, key, commit - _debug "**** Deploying $type *****" + type=$1 # Types are testkey, keygen, cert, key, commit + _debug "**** Deploying $type ****" panos_url="https://$_panos_host/api/" + + #Test API Key by performing an empty commit. + if [ "$type" = 'testkey' ]; then + _H1="Content-Type: application/x-www-form-urlencoded" + content="type=commit&cmd=&key=$_panos_key" + fi + + # Generate API Key if [ "$type" = 'keygen' ]; then _H1="Content-Type: application/x-www-form-urlencoded" content="type=keygen&user=$_panos_user&password=$_panos_pass" @@ -134,8 +146,22 @@ panos_deploy() { _err "Please pass username and password and host as env variables PANOS_USER, PANOS_PASS and PANOS_HOST" return 1 else - _debug "Getting PANOS KEY" - deployer keygen + #Check for saved API Key + _getdeployconf PANOS_KEY + _panos_key=$PANOS_KEY + if [ "$_panos_key" ]; then + _debug "**** Testing Saved API KEY ****" + deployer testkey + fi + + # Generate a new API key if needed + if [ -z "$_panos_key" ]; then + _debug "**** Generating new PANOS API KEY ****" + deployer keygen + _savedeployconf PANOS_KEY "$_panos_key" 1 + fi + + # Recheck the key if [ -z "$_panos_key" ]; then _err "Missing apikey." return 1 From 7623025b9007386281d64275978d41a0c52a1bf3 Mon Sep 17 00:00:00 2001 From: sg1888 Date: Mon, 24 Apr 2023 18:45:50 +0000 Subject: [PATCH 09/55] Fixes for POSIX sh shell --- deploy/panos.sh | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index 8edf115b..7fb0c9db 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -10,6 +10,7 @@ # export PANOS_USER="" # required # export PANOS_PASS="" # required # export PANOS_HOST="" # required +# export PANOS_KEY="" # optional # This function is to parse the XML parse_response() { @@ -25,7 +26,7 @@ parse_response() { else status=$(echo "$1" | sed 's/^.*"\([a-z]*\)".*/\1/g') message=$(echo "$1" | sed 's/^.*\(.*\)<\/result.*/\1/g') - if [ "$type" = 'testkey' ] && [ "$status" != "success" ]; then + if [ "$type" = 'testkey' ] && [ "$status" != "success" ]; then _debug "**** Saved API key is invalid ****" unset _panos_key fi @@ -38,7 +39,7 @@ deployer() { type=$1 # Types are testkey, keygen, cert, key, commit _debug "**** Deploying $type ****" panos_url="https://$_panos_host/api/" - + #Test API Key by performing an empty commit. if [ "$type" = 'testkey' ]; then _H1="Content-Type: application/x-www-form-urlencoded" @@ -104,16 +105,17 @@ deployer() { # This is the main function that will call the other functions to deploy everything. panos_deploy() { - _cdomain=${1//[*]/WILDCARD_} #Wildcard Safe filename + _cdomain=$(echo "$1" | sed 's/*/WILDCARD_/g') #Wildcard Safe Filename _ckey="$2" _cfullchain="$5" # VALID ECC KEY CHECK - if [[ "${_ckey: -8}" == "_ecc.key" ]] && [[ ! -f $_ckey ]]; then - _debug "The ECC key $_ckey doesn't exist. Attempting to strip _ecc from the filename" - _ckey="${_ckey:0:${#_ckey}-8}.key" - if [[ ! -f $_ckey ]]; then - _err "Still didn't work. Try issuing the certificate using RSA (non-ECC) encryption." - return 1 + keysuffix=$(printf '%s' "$_ckey" | tail -c 8) + if [ "$keysuffix" = "_ecc.key" ] && [ ! -f "$_ckey" ]; then + _debug "The ECC key $_ckey doesn't exist. Attempting to strip '_ecc' from the key name" + _ckey=$(echo "$_ckey" | sed 's/\(.*\)_ecc.key$/\1.key/g') + if [ ! -f "$_ckey" ]; then + _err "Unable to find a valid key. Try issuing the certificate using RSA (non-ECC) encryption." + return 1 fi fi # PANOS ENV VAR check @@ -122,9 +124,11 @@ panos_deploy() { _getdeployconf PANOS_USER _getdeployconf PANOS_PASS _getdeployconf PANOS_HOST + _getdeployconf PANOS_KEY _panos_user=$PANOS_USER _panos_pass=$PANOS_PASS _panos_host=$PANOS_HOST + _panos_key=$PANOS_KEY if [ -z "$_panos_user" ] && [ -z "$_panos_pass" ] && [ -z "$_panos_host" ]; then _err "No host, user and pass found.. If this is the first time deploying please set PANOS_HOST, PANOS_USER and PANOS_PASS in environment variables. Delete them after you have succesfully deployed certs." return 1 @@ -140,28 +144,33 @@ panos_deploy() { _panos_user="$PANOS_USER" _panos_pass="$PANOS_PASS" _panos_host="$PANOS_HOST" + if [ "$PANOS_KEY" ]; then + _savedeployconf PANOS_KEY "$PANOS_KEY" 1 + _panos_key="$PANOS_KEY" + else + _getdeployconf PANOS_KEY + _panos_key=$PANOS_KEY + fi fi _debug "Let's use username and pass to generate token." if [ -z "$_panos_user" ] || [ -z "$_panos_pass" ] || [ -z "$_panos_host" ]; then _err "Please pass username and password and host as env variables PANOS_USER, PANOS_PASS and PANOS_HOST" return 1 else - #Check for saved API Key - _getdeployconf PANOS_KEY - _panos_key=$PANOS_KEY + #Test API Key if [ "$_panos_key" ]; then _debug "**** Testing Saved API KEY ****" deployer testkey fi - # Generate a new API key if needed + # Generate a new API key if no valid key exists if [ -z "$_panos_key" ]; then _debug "**** Generating new PANOS API KEY ****" deployer keygen _savedeployconf PANOS_KEY "$_panos_key" 1 fi - # Recheck the key + # Confirm that a valid key was generated if [ -z "$_panos_key" ]; then _err "Missing apikey." return 1 From a8fba65cbd06d2bf1a25895a24c17f3c04f2dbca Mon Sep 17 00:00:00 2001 From: sg1888 Date: Mon, 15 May 2023 01:43:54 +0000 Subject: [PATCH 10/55] Cleaned up verbiage. Added ability to store / update user variable. Added ability to use user/pass OR key --- deploy/panos.sh | 144 ++++++++++++++++++++++++++++++------------------ 1 file changed, 90 insertions(+), 54 deletions(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index 7fb0c9db..774060b0 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -7,10 +7,24 @@ # # Firewall admin with superuser and IP address is required. # -# export PANOS_USER="" # required -# export PANOS_PASS="" # required -# export PANOS_HOST="" # required -# export PANOS_KEY="" # optional +# You MUST include the following environment variable when first running +# the sccript (can be deleted afterwards): +# +# REQURED: +# export PANOS_HOST="" # required +# +# AND one of the two authenticiation methods: +# +# Method 1: Username & Password (RECOMMENDED) +# export PANOS_USER="" +# export PANOS_PASS="" +# +# Method 2: API KEY +# export PANOS_KEY="" +# +# +# The Username & Password method will automatically generate a new API key if +# no key is found, or if a saved key has expired or is invalid. # This function is to parse the XML parse_response() { @@ -26,8 +40,8 @@ parse_response() { else status=$(echo "$1" | sed 's/^.*"\([a-z]*\)".*/\1/g') message=$(echo "$1" | sed 's/^.*\(.*\)<\/result.*/\1/g') - if [ "$type" = 'testkey' ] && [ "$status" != "success" ]; then - _debug "**** Saved API key is invalid ****" + if [ "$type" = 'keytest' ] && [ "$status" != "success" ]; then + _debug "**** API Key has EXPIRED or is INVALID ****" unset _panos_key fi fi @@ -36,25 +50,27 @@ parse_response() { deployer() { content="" - type=$1 # Types are testkey, keygen, cert, key, commit - _debug "**** Deploying $type ****" + type=$1 # Types are keytest, keygen, cert, key, commit panos_url="https://$_panos_host/api/" #Test API Key by performing an empty commit. - if [ "$type" = 'testkey' ]; then + if [ "$type" = 'keytest' ]; then + _debug "**** Testing saved API Key ****" _H1="Content-Type: application/x-www-form-urlencoded" content="type=commit&cmd=&key=$_panos_key" fi # Generate API Key if [ "$type" = 'keygen' ]; then + _debug "**** Generating new API Key ****" _H1="Content-Type: application/x-www-form-urlencoded" content="type=keygen&user=$_panos_user&password=$_panos_pass" # content="$content${nl}--$delim${nl}Content-Disposition: form-data; type=\"keygen\"; user=\"$_panos_user\"; password=\"$_panos_pass\"${nl}Content-Type: application/octet-stream${nl}${nl}" fi if [ "$type" = 'cert' ] || [ "$type" = 'key' ]; then - #Generate DEIM + _debug "**** Deploying $type ****" + #Generate DELIM delim="-----MultipartDelimiter$(date "+%s%N")" nl="\015\012" #Set Header @@ -83,8 +99,14 @@ deployer() { fi if [ "$type" = 'commit' ]; then + _debug "**** Committing changes ****" export _H1="Content-Type: application/x-www-form-urlencoded" - cmd=$(printf "%s" "<$_panos_user>" | _url_encode) + if [ "$_panos_user" ]; then + _commit_desc=$_panos_user + else + _commit_desc="acmesh" + fi + cmd=$(printf "%s" "<$_commit_desc>" | _url_encode) content="type=commit&key=$_panos_key&cmd=$cmd" fi response=$(_post "$content" "$panos_url" "" "POST") @@ -118,52 +140,66 @@ panos_deploy() { return 1 fi fi - # PANOS ENV VAR check - if [ -z "$PANOS_USER" ] || [ -z "$PANOS_PASS" ] || [ -z "$PANOS_HOST" ]; then - _debug "No ENV variables found lets check for saved variables" - _getdeployconf PANOS_USER - _getdeployconf PANOS_PASS - _getdeployconf PANOS_HOST - _getdeployconf PANOS_KEY - _panos_user=$PANOS_USER - _panos_pass=$PANOS_PASS - _panos_host=$PANOS_HOST - _panos_key=$PANOS_KEY - if [ -z "$_panos_user" ] && [ -z "$_panos_pass" ] && [ -z "$_panos_host" ]; then - _err "No host, user and pass found.. If this is the first time deploying please set PANOS_HOST, PANOS_USER and PANOS_PASS in environment variables. Delete them after you have succesfully deployed certs." - return 1 - else - _debug "Using saved env variables." - fi - else - _debug "Detected ENV variables to be saved to the deploy conf." - # Encrypt and save user - _savedeployconf PANOS_USER "$PANOS_USER" 1 - _savedeployconf PANOS_PASS "$PANOS_PASS" 1 + + # Environment Checks + + # PANOS_HOST + if [ "$PANOS_HOST" ]; then + _debug "Detected ENV variable PANOS_HOST. Saving to file." _savedeployconf PANOS_HOST "$PANOS_HOST" 1 - _panos_user="$PANOS_USER" - _panos_pass="$PANOS_PASS" - _panos_host="$PANOS_HOST" - if [ "$PANOS_KEY" ]; then - _savedeployconf PANOS_KEY "$PANOS_KEY" 1 - _panos_key="$PANOS_KEY" - else - _getdeployconf PANOS_KEY - _panos_key=$PANOS_KEY - fi + else + _debug "Attempting to load variable PANOS_HOST from file." + _getdeployconf PANOS_HOST fi - _debug "Let's use username and pass to generate token." - if [ -z "$_panos_user" ] || [ -z "$_panos_pass" ] || [ -z "$_panos_host" ]; then - _err "Please pass username and password and host as env variables PANOS_USER, PANOS_PASS and PANOS_HOST" + + # PANOS USER + if [ "$PANOS_USER" ]; then + _debug "Detected ENV variable PANOS_USER. Saving to file." + _savedeployconf PANOS_USER "$PANOS_USER" 1 + else + _debug "Attempting to load variable PANOS_USER from file." + _getdeployconf PANOS_USER + fi + + # PANOS_KEY + if [ "$PANOS_PASS" ]; then + _debug "Detected ENV variable PANOS_PASS. Saving to file." + _savedeployconf PANOS_PASS "$PANOS_PASS" 1 + else + _debug "Attempting to load variable PANOS_PASS from file." + _getdeployconf PANOS_PASS + fi + + # PANOS_KEY + if [ "$PANOS_KEY" ]; then + _debug "Detected ENV variable PANOS_KEY. Saving to file." + _savedeployconf PANOS_KEY "$PANOS_KEY" 1 + else + _debug "Attempting to load variable PANOS_KEY from file." + _getdeployconf PANOS_KEY + fi + + #Store variables + _panos_host=$PANOS_HOST + _panos_key=$PANOS_KEY + _panos_user=$PANOS_USER + _panos_pass=$PANOS_PASS + + #Test API Key if found. If the key is invalid, the variable panos_key will be unset. + if [ "$_panos_host" ] && [ "$_panos_key" ]; then + _debug "**** Testing API KEY ****" + deployer keytest + fi + + # Check for valid variables + if [ -z "$_panos_host" ]; then + _err "No host found. Please enter a valid host as environment variable PANOS_HOST." + return 1 + elif [ -z "$_panos_key" ] && { [ -z "$_panos_user" ] || [ -z "$_panos_pass" ]; }; then + _err "No user and pass OR valid API key found.. If this is the first time deploying please set PANOS_USER and PANOS_PASS -- AND/OR -- PANOS_KEY in environment variables. Delete them after you have succesfully deployed certs." return 1 else - #Test API Key - if [ "$_panos_key" ]; then - _debug "**** Testing Saved API KEY ****" - deployer testkey - fi - - # Generate a new API key if no valid key exists + # Generate a new API key if no valid API key is found if [ -z "$_panos_key" ]; then _debug "**** Generating new PANOS API KEY ****" deployer keygen @@ -172,7 +208,7 @@ panos_deploy() { # Confirm that a valid key was generated if [ -z "$_panos_key" ]; then - _err "Missing apikey." + _err "Unable to generate an API key. The user and pass may be invalid or not authorized to generate a new key. Please check the credentials and try again" return 1 else deployer cert From 0ebc9f7a44f05f595084e55b83cff59b471b8d9f Mon Sep 17 00:00:00 2001 From: sg1888 Date: Mon, 15 May 2023 01:46:21 +0000 Subject: [PATCH 11/55] Fixed typo --- deploy/panos.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index 774060b0..755ad5c9 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -161,7 +161,7 @@ panos_deploy() { _getdeployconf PANOS_USER fi - # PANOS_KEY + # PANOS_PASS if [ "$PANOS_PASS" ]; then _debug "Detected ENV variable PANOS_PASS. Saving to file." _savedeployconf PANOS_PASS "$PANOS_PASS" 1 From 2e2e7cd05408f8bf98016c5c0c9762608cd4e681 Mon Sep 17 00:00:00 2001 From: sg1888 Date: Wed, 17 May 2023 20:06:06 +0000 Subject: [PATCH 12/55] Added ability to force commit to firewall. Username is now also mandatory --- deploy/panos.sh | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index 755ad5c9..2744ba6d 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -7,26 +7,24 @@ # # Firewall admin with superuser and IP address is required. # -# You MUST include the following environment variable when first running -# the sccript (can be deleted afterwards): -# # REQURED: # export PANOS_HOST="" # required +# export PANOS_USER="" # required # # AND one of the two authenticiation methods: # -# Method 1: Username & Password (RECOMMENDED) -# export PANOS_USER="" +# Method 1: Password (RECOMMENDED) # export PANOS_PASS="" # # Method 2: API KEY # export PANOS_KEY="" # # -# The Username & Password method will automatically generate a new API key if +# The Password method will automatically generate a new API key if # no key is found, or if a saved key has expired or is invalid. +# -# This function is to parse the XML +# This function is to parse the XML response from the firewall parse_response() { type=$2 if [ "$type" = 'keygen' ]; then @@ -48,6 +46,7 @@ parse_response() { return 0 } +#This function is used to deploy to the firewall deployer() { content="" type=$1 # Types are keytest, keygen, cert, key, commit @@ -68,6 +67,7 @@ deployer() { # content="$content${nl}--$delim${nl}Content-Disposition: form-data; type=\"keygen\"; user=\"$_panos_user\"; password=\"$_panos_pass\"${nl}Content-Type: application/octet-stream${nl}${nl}" fi + # Deploy Cert or Key if [ "$type" = 'cert' ] || [ "$type" = 'key' ]; then _debug "**** Deploying $type ****" #Generate DELIM @@ -98,17 +98,19 @@ deployer() { content=$(printf %b "$content") fi + # Commit changes if [ "$type" = 'commit' ]; then _debug "**** Committing changes ****" export _H1="Content-Type: application/x-www-form-urlencoded" - if [ "$_panos_user" ]; then - _commit_desc=$_panos_user + #Check for force commit + if [ "$FORCE" ]; then + cmd=$(printf "%s" "<$_panos_user>" | _url_encode) else - _commit_desc="acmesh" + cmd=$(printf "%s" "<$_panos_user>" | _url_encode) fi - cmd=$(printf "%s" "<$_commit_desc>" | _url_encode) content="type=commit&key=$_panos_key&cmd=$cmd" fi + response=$(_post "$content" "$panos_url" "" "POST") parse_response "$response" "$type" # Saving response to variables @@ -141,8 +143,6 @@ panos_deploy() { fi fi - # Environment Checks - # PANOS_HOST if [ "$PANOS_HOST" ]; then _debug "Detected ENV variable PANOS_HOST. Saving to file." @@ -193,10 +193,13 @@ panos_deploy() { # Check for valid variables if [ -z "$_panos_host" ]; then - _err "No host found. Please enter a valid host as environment variable PANOS_HOST." + _err "No host found. If this is your first time deploying, please set PANOS_HOST in ENV variables. You can delete it after you have successfully deployed the certs." + return 1 + elif [ -z "$_panos_user" ]; then + _err "No user found. If this is your first time deploying, please set PANOS_USER in ENV variables. You can delete it after you have successfully deployed certs." return 1 elif [ -z "$_panos_key" ] && { [ -z "$_panos_user" ] || [ -z "$_panos_pass" ]; }; then - _err "No user and pass OR valid API key found.. If this is the first time deploying please set PANOS_USER and PANOS_PASS -- AND/OR -- PANOS_KEY in environment variables. Delete them after you have succesfully deployed certs." + _err "No pass OR valid API key found. If this is your first time deploying please set PANOS_PASS and/or PANOS_KEY in ENV variables. You can delete them after you have succesfully deployed certs." return 1 else # Generate a new API key if no valid API key is found @@ -208,7 +211,7 @@ panos_deploy() { # Confirm that a valid key was generated if [ -z "$_panos_key" ]; then - _err "Unable to generate an API key. The user and pass may be invalid or not authorized to generate a new key. Please check the credentials and try again" + _err "Unable to generate an API key. The user and pass may be invalid or not authorized to generate a new key. Please check the PANOS_USER and PANOS_PASS credentials and try again" return 1 else deployer cert From 126df9647b6ef11da3a7efe9897b453cf4e501d9 Mon Sep 17 00:00:00 2001 From: sg1888 Date: Wed, 24 May 2023 18:51:57 +0000 Subject: [PATCH 13/55] Modified keytest to perform a partial empty commit --- deploy/panos.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index 2744ba6d..880e4cec 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -56,7 +56,7 @@ deployer() { if [ "$type" = 'keytest' ]; then _debug "**** Testing saved API Key ****" _H1="Content-Type: application/x-www-form-urlencoded" - content="type=commit&cmd=&key=$_panos_key" + content="type=commit&key=$_panos_key&action=partial&cmd=acmekeytest" fi # Generate API Key @@ -132,6 +132,7 @@ panos_deploy() { _cdomain=$(echo "$1" | sed 's/*/WILDCARD_/g') #Wildcard Safe Filename _ckey="$2" _cfullchain="$5" + # VALID ECC KEY CHECK keysuffix=$(printf '%s' "$_ckey" | tail -c 8) if [ "$keysuffix" = "_ecc.key" ] && [ ! -f "$_ckey" ]; then @@ -196,10 +197,10 @@ panos_deploy() { _err "No host found. If this is your first time deploying, please set PANOS_HOST in ENV variables. You can delete it after you have successfully deployed the certs." return 1 elif [ -z "$_panos_user" ]; then - _err "No user found. If this is your first time deploying, please set PANOS_USER in ENV variables. You can delete it after you have successfully deployed certs." + _err "No user found. If this is your first time deploying, please set PANOS_USER in ENV variables. You can delete it after you have successfully deployed the certs." return 1 elif [ -z "$_panos_key" ] && { [ -z "$_panos_user" ] || [ -z "$_panos_pass" ]; }; then - _err "No pass OR valid API key found. If this is your first time deploying please set PANOS_PASS and/or PANOS_KEY in ENV variables. You can delete them after you have succesfully deployed certs." + _err "No pass OR valid API key found. If this is your first time deploying please set PANOS_PASS and/or PANOS_KEY in ENV variables. You can delete them after you have succesfully deployed the certs." return 1 else # Generate a new API key if no valid API key is found From 63fca33b0459b1483c91c38a9ae3060bb6ef621a Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Mon, 29 May 2023 20:12:52 +0200 Subject: [PATCH 14/55] Fix retrieval of domain zone --- dnsapi/dns_artfiles.sh | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/dnsapi/dns_artfiles.sh b/dnsapi/dns_artfiles.sh index 2f8e158f..703c02ac 100644 --- a/dnsapi/dns_artfiles.sh +++ b/dnsapi/dns_artfiles.sh @@ -140,14 +140,13 @@ _dns() { # Gets the root domain zone for given domain. # Usage: _get_zone _acme-challenge.www.example.com _get_zone() { - _info 'Getting domain zone...' - _debug2 'Initial FQDN' "$1" fqdn="$1" - fqdn="${fqdn#*.}" # Strip "_acme-challenge" right away - _debug2 'Reduced FQDN' "$fqdn" + domains="$(_get "$AF_URL_DOMAINS" "" 10)" + _info 'Getting domain zone...' + _debug2 'FQDN' "$fqdn" + _debug2 'Domains' "$domains" - domains="$(_get "$AF_URL_DOMAINS" '' 10)" - while true; do + while _contains "$fqdn" "."; do if _contains "$domains" "$fqdn"; then domain="$fqdn" _info "Found root domain zone: $domain" @@ -162,7 +161,7 @@ _get_zone() { return 0 fi - _err "Couldn't find root domain zone." + _err 'Couldn\'t find root domain zone.' return 1 } From fb33ea2a0b6fc8ff260da123709b0872c6b91e79 Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Mon, 29 May 2023 20:21:16 +0200 Subject: [PATCH 15/55] Fix single quote escaping --- dnsapi/dns_artfiles.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_artfiles.sh b/dnsapi/dns_artfiles.sh index 703c02ac..ad547e3f 100644 --- a/dnsapi/dns_artfiles.sh +++ b/dnsapi/dns_artfiles.sh @@ -161,7 +161,7 @@ _get_zone() { return 0 fi - _err 'Couldn\'t find root domain zone.' + _err 'Couldn'\''t find root domain zone.' return 1 } From d108072bfbc057f895d29620a8ecd6752ebe47f6 Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Tue, 30 May 2023 09:24:17 +0200 Subject: [PATCH 16/55] Add ArtFiles.de DNS API plugin --- dnsapi/dns_artfiles.sh | 175 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 dnsapi/dns_artfiles.sh diff --git a/dnsapi/dns_artfiles.sh b/dnsapi/dns_artfiles.sh new file mode 100644 index 00000000..ad547e3f --- /dev/null +++ b/dnsapi/dns_artfiles.sh @@ -0,0 +1,175 @@ +#!/usr/bin/env sh + +################################################################################ +# ACME.sh 3rd party DNS API plugin for ArtFiles.de +################################################################################ +# Author: Martin Arndt, https://troublezone.net/ +# Released: 2022-02-27 +# Issues: https://github.com/Eagle3386/acme.sh/issues +################################################################################ +# Usage: +# 1. export AF_API_USERNAME="api12345678" +# 2. export AF_API_PASSWORD="apiPassword" +# 3. acme.sh --issue -d example.com --dns dns_artfiles +################################################################################ + +########## API configuration ################################################### +AF_API_SUCCESS='status":"OK' +AF_URL_DCP='https://dcp.c.artfiles.de/api/' +AF_URL_DNS=${AF_URL_DCP}'dns/{*}_dns.html?domain=' +AF_URL_DOMAINS=${AF_URL_BASE}'domain/get_domains.html' + +########## Public functions #################################################### + +# Adds a new TXT record for given ACME challenge value & domain. +# Usage: dns_artfiles_add _acme-challenge.www.example.com "ACME challenge value" +dns_artfiles_add() { + domain="$1" + txtValue="$2" + _info 'Using ArtFiles.de DNS addition API' + _debug 'Domain' "$domain" + _debug 'txtValue' "$txtValue" + + AF_API_USERNAME="${AF_API_USERNAME:-$(_readaccountconf_mutable AF_API_USERNAME)}" + AF_API_PASSWORD="${AF_API_PASSWORD:-$(_readaccountconf_mutable AF_API_PASSWORD)}" + if [ -z "$AF_API_USERNAME" ] || [ -z "$AF_API_PASSWORD" ]; then + _err 'Missing ArtFiles.de username and/or password.' + _err 'Please ensure both are set via export command & try again.' + + return 1 + fi + + _saveaccountconf_mutable 'AF_API_USERNAME' "$AF_API_USERNAME" + _saveaccountconf_mutable 'AF_API_PASSWORD' "$AF_API_PASSWORD" + + _set_headers + _get_zone "$domain" + _dns 'GET' + if ! _contains "$response" 'TXT'; then + _err 'Retrieving TXT records failed.' + + return 1 + fi + + _clean_records + _dns 'SET' "$(printf -- '%s\n_acme-challenge "%s"' "$response" "$txtValue")" + if ! _contains "$response" "$AF_API_SUCCESS"; then + _err 'Adding ACME challenge value failed.' + + return 1 + fi +} + +# Removes the existing TXT record for given ACME challenge value & domain. +# Usage: dns_artfiles_rm _acme-challenge.www.example.com "ACME challenge value" +dns_artfiles_rm() { + domain="$1" + txtValue="$2" + _info 'Using ArtFiles.de DNS removal API' + _debug 'Domain' "$domain" + _debug 'txtValue' "$txtValue" + + _set_headers + _get_zone "$domain" + if ! _dns 'GET'; then + return 1 + fi + + if ! _contains "$response" "$txtValue"; then + _err 'Retrieved TXT records are missing given ACME challenge value.' + + return 1 + fi + + _clean_records + response="$(printf -- '%s' "$response" | sed '$d')" + _dns 'SET' "$response" + if ! _contains "$response" "$AF_API_SUCCESS"; then + _err 'Removing ACME challenge value failed.' + + return 1 + fi +} + +########## Private functions ################################################### + +# Cleans awful TXT records response of ArtFiles's API & pretty prints it. +# Usage: _clean_records +_clean_records() { + # Extract TXT part, strip trailing quote sign (ACME.sh API guidelines forbid + # usage of SED's GNU extensions, hence couldn't omit it via regex), strip '\' + # from '\"' & turn '\n' into real LF characters. + # Yup, awful API to use - but that's all we got to get this working, so... ;) + _debug2 'Raw ' "$response" + response="$( + printf -- '%s' "$response" + \ | sed 's/^\(.*TXT":"\)\([^,}]*\)\(.*\)$/\2/;s/.$//;s/\\"/"/g;s/\\n/\n/g' + )" + _debug2 'Clean' "$response" +} + +# Executes an HTTP GET or POST request for getting or setting DNS records, +# containing given payload upon POST. +# Usage: _dns [GET | SET] [payload] +_dns() { + action="$1" + payload="$(printf -- '%s' "$2" | _url_encode)" + url="$( + printf -- '%s%s' "$AF_URL_DNS" "$domain" + \ | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/' + )" + + if [ "$action" = 'SET' ]; then + _debug2 'Payload' "$payload" + response="$(_post '' "$url&TXT=$payload" '' 'POST' 'application/x-www-form-urlencoded')" + else + response="$(_get "$url" '' 10)" + fi + + if ! _contains "$response" "$AF_API_SUCCESS"; then + _err "DNS API error: $response" + + return 1 + fi + + _debug 'Response' "$response" + + return 0 +} + +# Gets the root domain zone for given domain. +# Usage: _get_zone _acme-challenge.www.example.com +_get_zone() { + fqdn="$1" + domains="$(_get "$AF_URL_DOMAINS" "" 10)" + _info 'Getting domain zone...' + _debug2 'FQDN' "$fqdn" + _debug2 'Domains' "$domains" + + while _contains "$fqdn" "."; do + if _contains "$domains" "$fqdn"; then + domain="$fqdn" + _info "Found root domain zone: $domain" + break + else + fqdn="${fqdn#*.}" + _debug2 'FQDN' "$fqdn" + fi + done + + if [ "$domain" = "$fqdn" ]; then + return 0 + fi + + _err 'Couldn'\''t find root domain zone.' + + return 1 +} + +# Adds the HTTP Authorization & Content-Type headers to a follow-up request. +# Usage: _set_headers +_set_headers() { + encoded="$(printf -- '%s:%s' "$AF_API_USERNAME" "$AF_API_PASSWORD" | _base64)" + export _H1="Authorization: Basic $encoded" + export _H2='Content-Type: application/json' +} From db8a2d0c653ba19df024c8289942166d7e5bb025 Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Wed, 5 Jul 2023 11:05:06 +0200 Subject: [PATCH 17/55] Fix & improve DNS API for ArtFiles.de --- dnsapi/dns_artfiles.sh | 80 ++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/dnsapi/dns_artfiles.sh b/dnsapi/dns_artfiles.sh index ad547e3f..6224c416 100644 --- a/dnsapi/dns_artfiles.sh +++ b/dnsapi/dns_artfiles.sh @@ -5,40 +5,34 @@ ################################################################################ # Author: Martin Arndt, https://troublezone.net/ # Released: 2022-02-27 -# Issues: https://github.com/Eagle3386/acme.sh/issues +# Issues: https://github.com/acmesh-official/acme.sh/issues/XXXX ################################################################################ # Usage: -# 1. export AF_API_USERNAME="api12345678" -# 2. export AF_API_PASSWORD="apiPassword" +# 1. export AF_API_USERNAME='api12345678' +# 2. export AF_API_PASSWORD='apiPassword' # 3. acme.sh --issue -d example.com --dns dns_artfiles ################################################################################ ########## API configuration ################################################### + AF_API_SUCCESS='status":"OK' AF_URL_DCP='https://dcp.c.artfiles.de/api/' AF_URL_DNS=${AF_URL_DCP}'dns/{*}_dns.html?domain=' -AF_URL_DOMAINS=${AF_URL_BASE}'domain/get_domains.html' +AF_URL_DOMAINS=${AF_URL_DCP}'domain/get_domains.html' ########## Public functions #################################################### # Adds a new TXT record for given ACME challenge value & domain. # Usage: dns_artfiles_add _acme-challenge.www.example.com "ACME challenge value" -dns_artfiles_add() { +dns_artfiles_add() +{ domain="$1" txtValue="$2" - _info 'Using ArtFiles.de DNS addition API' + _info 'Using ArtFiles.de DNS addition API…' _debug 'Domain' "$domain" _debug 'txtValue' "$txtValue" - AF_API_USERNAME="${AF_API_USERNAME:-$(_readaccountconf_mutable AF_API_USERNAME)}" - AF_API_PASSWORD="${AF_API_PASSWORD:-$(_readaccountconf_mutable AF_API_PASSWORD)}" - if [ -z "$AF_API_USERNAME" ] || [ -z "$AF_API_PASSWORD" ]; then - _err 'Missing ArtFiles.de username and/or password.' - _err 'Please ensure both are set via export command & try again.' - - return 1 - fi - + _set_credentials _saveaccountconf_mutable 'AF_API_USERNAME' "$AF_API_USERNAME" _saveaccountconf_mutable 'AF_API_PASSWORD' "$AF_API_PASSWORD" @@ -62,13 +56,15 @@ dns_artfiles_add() { # Removes the existing TXT record for given ACME challenge value & domain. # Usage: dns_artfiles_rm _acme-challenge.www.example.com "ACME challenge value" -dns_artfiles_rm() { +dns_artfiles_rm() +{ domain="$1" txtValue="$2" - _info 'Using ArtFiles.de DNS removal API' + _info 'Using ArtFiles.de DNS removal API…' _debug 'Domain' "$domain" _debug 'txtValue' "$txtValue" + _set_credentials _set_headers _get_zone "$domain" if ! _dns 'GET'; then @@ -95,29 +91,28 @@ dns_artfiles_rm() { # Cleans awful TXT records response of ArtFiles's API & pretty prints it. # Usage: _clean_records -_clean_records() { +_clean_records() +{ + _info 'Cleaning TXT records…' # Extract TXT part, strip trailing quote sign (ACME.sh API guidelines forbid # usage of SED's GNU extensions, hence couldn't omit it via regex), strip '\' # from '\"' & turn '\n' into real LF characters. - # Yup, awful API to use - but that's all we got to get this working, so... ;) + # Yup, awful API to use - but that's all we got to get this working, so… ;) _debug2 'Raw ' "$response" - response="$( - printf -- '%s' "$response" - \ | sed 's/^\(.*TXT":"\)\([^,}]*\)\(.*\)$/\2/;s/.$//;s/\\"/"/g;s/\\n/\n/g' - )" + + response="$(printf -- '%s' "$response" | sed 's/^.*TXT":"\([^}]*\).*$/\1/;s/,".*$//;s/.$//;s/\\"/"/g;s/\\n/\n/g')" _debug2 'Clean' "$response" } # Executes an HTTP GET or POST request for getting or setting DNS records, # containing given payload upon POST. # Usage: _dns [GET | SET] [payload] -_dns() { +_dns() +{ + _info 'Executing HTTP request…' action="$1" payload="$(printf -- '%s' "$2" | _url_encode)" - url="$( - printf -- '%s%s' "$AF_URL_DNS" "$domain" - \ | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/' - )" + url="$(printf -- '%s%s' "$AF_URL_DNS" "$domain" | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/')" if [ "$action" = 'SET' ]; then _debug2 'Payload' "$payload" @@ -139,10 +134,11 @@ _dns() { # Gets the root domain zone for given domain. # Usage: _get_zone _acme-challenge.www.example.com -_get_zone() { +_get_zone() +{ fqdn="$1" - domains="$(_get "$AF_URL_DOMAINS" "" 10)" - _info 'Getting domain zone...' + domains="$(_get "$AF_URL_DOMAINS" '' 10)" + _info 'Getting domain zone…' _debug2 'FQDN' "$fqdn" _debug2 'Domains' "$domains" @@ -166,10 +162,26 @@ _get_zone() { return 1 } +# Sets the credentials for accessing ArtFiles's API +# Usage: _set_credentials +_set_credentials() +{ + _info 'Setting credentials…' + AF_API_USERNAME="${AF_API_USERNAME:-$(_readaccountconf_mutable AF_API_USERNAME)}" + AF_API_PASSWORD="${AF_API_PASSWORD:-$(_readaccountconf_mutable AF_API_PASSWORD)}" + if [ -z "$AF_API_USERNAME" ] || [ -z "$AF_API_PASSWORD" ]; then + _err 'Missing ArtFiles.de username and/or password.' + _err 'Please ensure both are set via export command & try again.' + + return 1 + fi +} + # Adds the HTTP Authorization & Content-Type headers to a follow-up request. # Usage: _set_headers -_set_headers() { - encoded="$(printf -- '%s:%s' "$AF_API_USERNAME" "$AF_API_PASSWORD" | _base64)" - export _H1="Authorization: Basic $encoded" +_set_headers() +{ + _info 'Setting headers…' + export _H1="$(printf -- 'Authorization: Basic %s:%s' "$AF_API_USERNAME" "$AF_API_PASSWORD" | _base64)" export _H2='Content-Type: application/json' } From 2961a90e7ffb37ad498a8d841d00dbb2a08d251c Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Wed, 5 Jul 2023 11:14:49 +0200 Subject: [PATCH 18/55] Make ShellCheck & ShellFormat happy --- dnsapi/dns_artfiles.sh | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/dnsapi/dns_artfiles.sh b/dnsapi/dns_artfiles.sh index 6224c416..04cdf026 100644 --- a/dnsapi/dns_artfiles.sh +++ b/dnsapi/dns_artfiles.sh @@ -24,8 +24,7 @@ AF_URL_DOMAINS=${AF_URL_DCP}'domain/get_domains.html' # Adds a new TXT record for given ACME challenge value & domain. # Usage: dns_artfiles_add _acme-challenge.www.example.com "ACME challenge value" -dns_artfiles_add() -{ +dns_artfiles_add() { domain="$1" txtValue="$2" _info 'Using ArtFiles.de DNS addition API…' @@ -56,8 +55,7 @@ dns_artfiles_add() # Removes the existing TXT record for given ACME challenge value & domain. # Usage: dns_artfiles_rm _acme-challenge.www.example.com "ACME challenge value" -dns_artfiles_rm() -{ +dns_artfiles_rm() { domain="$1" txtValue="$2" _info 'Using ArtFiles.de DNS removal API…' @@ -91,15 +89,13 @@ dns_artfiles_rm() # Cleans awful TXT records response of ArtFiles's API & pretty prints it. # Usage: _clean_records -_clean_records() -{ +_clean_records() { _info 'Cleaning TXT records…' # Extract TXT part, strip trailing quote sign (ACME.sh API guidelines forbid # usage of SED's GNU extensions, hence couldn't omit it via regex), strip '\' # from '\"' & turn '\n' into real LF characters. # Yup, awful API to use - but that's all we got to get this working, so… ;) _debug2 'Raw ' "$response" - response="$(printf -- '%s' "$response" | sed 's/^.*TXT":"\([^}]*\).*$/\1/;s/,".*$//;s/.$//;s/\\"/"/g;s/\\n/\n/g')" _debug2 'Clean' "$response" } @@ -107,8 +103,7 @@ _clean_records() # Executes an HTTP GET or POST request for getting or setting DNS records, # containing given payload upon POST. # Usage: _dns [GET | SET] [payload] -_dns() -{ +_dns() { _info 'Executing HTTP request…' action="$1" payload="$(printf -- '%s' "$2" | _url_encode)" @@ -134,8 +129,7 @@ _dns() # Gets the root domain zone for given domain. # Usage: _get_zone _acme-challenge.www.example.com -_get_zone() -{ +_get_zone() { fqdn="$1" domains="$(_get "$AF_URL_DOMAINS" '' 10)" _info 'Getting domain zone…' @@ -164,8 +158,7 @@ _get_zone() # Sets the credentials for accessing ArtFiles's API # Usage: _set_credentials -_set_credentials() -{ +_set_credentials() { _info 'Setting credentials…' AF_API_USERNAME="${AF_API_USERNAME:-$(_readaccountconf_mutable AF_API_USERNAME)}" AF_API_PASSWORD="${AF_API_PASSWORD:-$(_readaccountconf_mutable AF_API_PASSWORD)}" @@ -179,9 +172,9 @@ _set_credentials() # Adds the HTTP Authorization & Content-Type headers to a follow-up request. # Usage: _set_headers -_set_headers() -{ +_set_headers() { _info 'Setting headers…' - export _H1="$(printf -- 'Authorization: Basic %s:%s' "$AF_API_USERNAME" "$AF_API_PASSWORD" | _base64)" + encoded="$(printf -- '%s:%s' "$AF_API_USERNAME" "$AF_API_PASSWORD" | _base64)" + export _H1="Authorization: Basic $encoded" export _H2='Content-Type: application/json' } From 8b3acb719eb6eee82ef40edff94ed2372ecdc1df Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Wed, 5 Jul 2023 13:04:08 +0200 Subject: [PATCH 19/55] Fix TXT record removal --- dnsapi/dns_artfiles.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_artfiles.sh b/dnsapi/dns_artfiles.sh index 04cdf026..faf8c2ae 100644 --- a/dnsapi/dns_artfiles.sh +++ b/dnsapi/dns_artfiles.sh @@ -76,7 +76,7 @@ dns_artfiles_rm() { fi _clean_records - response="$(printf -- '%s' "$response" | sed '$d')" + response="$(printf -- '%s' "$response" | sed '/_acme-challenge "'"$txtValue"'"/d')" _dns 'SET' "$response" if ! _contains "$response" "$AF_API_SUCCESS"; then _err 'Removing ACME challenge value failed.' From d86414febbaeeefe1ef563ada1882051ccd6c758 Mon Sep 17 00:00:00 2001 From: sg1888 Date: Tue, 11 Jul 2023 23:41:24 +0000 Subject: [PATCH 20/55] Excluded scopes for api key test --- deploy/panos.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index 880e4cec..2bb9f08f 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -56,7 +56,9 @@ deployer() { if [ "$type" = 'keytest' ]; then _debug "**** Testing saved API Key ****" _H1="Content-Type: application/x-www-form-urlencoded" - content="type=commit&key=$_panos_key&action=partial&cmd=acmekeytest" + #Exclude all scopes for the empty commit + _exclude_scope="excludeexcludeexclude" + content="type=commit&key=$_panos_key&cmd=$_exclude_scopeacmekeytest" fi # Generate API Key From e69a19db5c555c8a23fb31e1be393d0f220341fa Mon Sep 17 00:00:00 2001 From: sg1888 Date: Tue, 11 Jul 2023 23:56:41 +0000 Subject: [PATCH 21/55] Incorporated partial commit to address issue #4198 --- deploy/panos.sh | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index 2bb9f08f..f18482fc 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -36,8 +36,9 @@ parse_response() { message="PAN-OS Key could not be set." fi else - status=$(echo "$1" | sed 's/^.*"\([a-z]*\)".*/\1/g') - message=$(echo "$1" | sed 's/^.*\(.*\)<\/result.*/\1/g') + status=$(echo "$1" | tr -d '\n' | sed 's/^.*"\([a-z]*\)".*/\1/g') + message=$(echo "$1" | tr -d '\n' | sed 's/.*\(\|\|\)\([^<]*\).*/\2/g') + _debug "Firewall message: $message" if [ "$type" = 'keytest' ] && [ "$status" != "success" ]; then _debug "**** API Key has EXPIRED or is INVALID ****" unset _panos_key @@ -58,7 +59,7 @@ deployer() { _H1="Content-Type: application/x-www-form-urlencoded" #Exclude all scopes for the empty commit _exclude_scope="excludeexcludeexclude" - content="type=commit&key=$_panos_key&cmd=$_exclude_scopeacmekeytest" + content="type=commit&action=partial&key=$_panos_key&cmd=$_exclude_scopeacmekeytest" fi # Generate API Key @@ -104,20 +105,21 @@ deployer() { if [ "$type" = 'commit' ]; then _debug "**** Committing changes ****" export _H1="Content-Type: application/x-www-form-urlencoded" - #Check for force commit + #Check for force commit - will commit ALL uncommited changes to the firewall. Use with caution! if [ "$FORCE" ]; then - cmd=$(printf "%s" "<$_panos_user>" | _url_encode) + _debug "Force switch detected. Committing ALL changes to the firewall." + cmd=$(printf "%s" "$_panos_user" | _url_encode) else - cmd=$(printf "%s" "<$_panos_user>" | _url_encode) + _exclude_scope="excludeexclude" + cmd=$(printf "%s" "$_exclude_scope$_panos_user" | _url_encode) fi - content="type=commit&key=$_panos_key&cmd=$cmd" + content="type=commit&action=partial&key=$_panos_key&cmd=$cmd" fi response=$(_post "$content" "$panos_url" "" "POST") parse_response "$response" "$type" # Saving response to variables response_status=$status - #DEBUG _debug response_status "$response_status" if [ "$response_status" = "success" ]; then _debug "Successfully deployed $type" From b556908cab48cf71ad577f912693316eea1a7078 Mon Sep 17 00:00:00 2001 From: sg1888 Date: Wed, 12 Jul 2023 00:03:21 +0000 Subject: [PATCH 22/55] Modified ECC file test --- deploy/panos.sh | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index f18482fc..e11a6eed 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -137,15 +137,10 @@ panos_deploy() { _ckey="$2" _cfullchain="$5" - # VALID ECC KEY CHECK - keysuffix=$(printf '%s' "$_ckey" | tail -c 8) - if [ "$keysuffix" = "_ecc.key" ] && [ ! -f "$_ckey" ]; then - _debug "The ECC key $_ckey doesn't exist. Attempting to strip '_ecc' from the key name" - _ckey=$(echo "$_ckey" | sed 's/\(.*\)_ecc.key$/\1.key/g') - if [ ! -f "$_ckey" ]; then - _err "Unable to find a valid key. Try issuing the certificate using RSA (non-ECC) encryption." - return 1 - fi + # VALID FILE CHECK + if [ ! -f "$_ckey" ] || [ ! -f "$_cfullchain" ]; then + _err "Unable to find a valid key and/or cert. If this is an ECDSA/ECC cert, use the --ecc flag when deploying." + return 1 fi # PANOS_HOST From edd1b60c3d39269dc1c5ff15ea842f1a0d3624f2 Mon Sep 17 00:00:00 2001 From: sg1888 Date: Tue, 18 Jul 2023 19:43:47 +0000 Subject: [PATCH 23/55] Removed ability to specify API key to facilitate future multiple host functionality. --- deploy/panos.sh | 47 ++++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index e11a6eed..27919a25 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -8,21 +8,13 @@ # Firewall admin with superuser and IP address is required. # # REQURED: -# export PANOS_HOST="" # required -# export PANOS_USER="" # required -# -# AND one of the two authenticiation methods: -# -# Method 1: Password (RECOMMENDED) +# export PANOS_HOST="" +# export PANOS_USER="" #User *MUST* have Commit and Import Permissions in XML API for Admin Role # export PANOS_PASS="" # -# Method 2: API KEY -# export PANOS_KEY="" -# -# -# The Password method will automatically generate a new API key if +# The script will automatically generate a new API key if # no key is found, or if a saved key has expired or is invalid. -# + # This function is to parse the XML response from the firewall parse_response() { @@ -53,13 +45,15 @@ deployer() { type=$1 # Types are keytest, keygen, cert, key, commit panos_url="https://$_panos_host/api/" - #Test API Key by performing an empty commit. + #Test API Key by performing a lookup if [ "$type" = 'keytest' ]; then _debug "**** Testing saved API Key ****" _H1="Content-Type: application/x-www-form-urlencoded" - #Exclude all scopes for the empty commit - _exclude_scope="excludeexcludeexclude" - content="type=commit&action=partial&key=$_panos_key&cmd=$_exclude_scopeacmekeytest" + # Get Version Info to test key + content="type=version&key=$_panos_key" + ## Exclude all scopes for the empty commit + #_exclude_scope="excludeexcludeexclude" + #content="type=commit&action=partial&key=$_panos_key&cmd=$_exclude_scopeacmekeytest" fi # Generate API Key @@ -170,22 +164,17 @@ panos_deploy() { _getdeployconf PANOS_PASS fi - # PANOS_KEY - if [ "$PANOS_KEY" ]; then - _debug "Detected ENV variable PANOS_KEY. Saving to file." - _savedeployconf PANOS_KEY "$PANOS_KEY" 1 - else - _debug "Attempting to load variable PANOS_KEY from file." - _getdeployconf PANOS_KEY - fi - #Store variables _panos_host=$PANOS_HOST - _panos_key=$PANOS_KEY _panos_user=$PANOS_USER _panos_pass=$PANOS_PASS - #Test API Key if found. If the key is invalid, the variable panos_key will be unset. + #Load saved keys + _getdeployconf PANOS_KEY + _panos_key=$PANOS_KEY + + + #Test API Key if found. If the key is invalid, the variable _panos_key will be unset. if [ "$_panos_host" ] && [ "$_panos_key" ]; then _debug "**** Testing API KEY ****" deployer keytest @@ -198,8 +187,8 @@ panos_deploy() { elif [ -z "$_panos_user" ]; then _err "No user found. If this is your first time deploying, please set PANOS_USER in ENV variables. You can delete it after you have successfully deployed the certs." return 1 - elif [ -z "$_panos_key" ] && { [ -z "$_panos_user" ] || [ -z "$_panos_pass" ]; }; then - _err "No pass OR valid API key found. If this is your first time deploying please set PANOS_PASS and/or PANOS_KEY in ENV variables. You can delete them after you have succesfully deployed the certs." + elif [ -z "$_panos_pass" ]; then + _err "No password found. If this is your first time deploying, please set PANOS_PASS in ENV variables. You can delete it after you have successfully deployed the certs." return 1 else # Generate a new API key if no valid API key is found From ae035deb92b1557832fa06e4ebecd0519df6c8b4 Mon Sep 17 00:00:00 2001 From: sg1888 Date: Tue, 18 Jul 2023 20:10:31 +0000 Subject: [PATCH 24/55] Fixed shell check errors --- deploy/panos.sh | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index 27919a25..efc1a656 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -15,7 +15,6 @@ # The script will automatically generate a new API key if # no key is found, or if a saved key has expired or is invalid. - # This function is to parse the XML response from the firewall parse_response() { type=$2 @@ -130,6 +129,8 @@ panos_deploy() { _cdomain=$(echo "$1" | sed 's/*/WILDCARD_/g') #Wildcard Safe Filename _ckey="$2" _cfullchain="$5" + _regen_keys=false #Flag to regenerate keys if PANOS_USER or PANOS_PASS changes. + # VALID FILE CHECK if [ ! -f "$_ckey" ] || [ ! -f "$_cfullchain" ]; then @@ -164,15 +165,22 @@ panos_deploy() { _getdeployconf PANOS_PASS fi + # PANOS_KEY + _getdeployconf PANOS_KEY + if [ "$PANOS_KEY" ]; then + _debug "Detected saved key." + _panos_key=$PANOS_KEY + else + _debug "No key detected" + unset _panos_key + fi + + #Store variables _panos_host=$PANOS_HOST _panos_user=$PANOS_USER _panos_pass=$PANOS_PASS - #Load saved keys - _getdeployconf PANOS_KEY - _panos_key=$PANOS_KEY - #Test API Key if found. If the key is invalid, the variable _panos_key will be unset. if [ "$_panos_host" ] && [ "$_panos_key" ]; then From 02de281e40ecebd2e68a12d92066f44303b57348 Mon Sep 17 00:00:00 2001 From: sg1888 Date: Tue, 18 Jul 2023 20:15:46 +0000 Subject: [PATCH 25/55] Removed unused variable --- deploy/panos.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index efc1a656..9e48e4b3 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -129,7 +129,6 @@ panos_deploy() { _cdomain=$(echo "$1" | sed 's/*/WILDCARD_/g') #Wildcard Safe Filename _ckey="$2" _cfullchain="$5" - _regen_keys=false #Flag to regenerate keys if PANOS_USER or PANOS_PASS changes. # VALID FILE CHECK From 1984f44ffe1e192c4d0b66fd026df4aa29801684 Mon Sep 17 00:00:00 2001 From: sg1888 Date: Tue, 18 Jul 2023 20:18:12 +0000 Subject: [PATCH 26/55] Shell formatting --- deploy/panos.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/deploy/panos.sh b/deploy/panos.sh index 9e48e4b3..89458e5f 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -130,7 +130,6 @@ panos_deploy() { _ckey="$2" _cfullchain="$5" - # VALID FILE CHECK if [ ! -f "$_ckey" ] || [ ! -f "$_cfullchain" ]; then _err "Unable to find a valid key and/or cert. If this is an ECDSA/ECC cert, use the --ecc flag when deploying." @@ -174,13 +173,11 @@ panos_deploy() { unset _panos_key fi - #Store variables _panos_host=$PANOS_HOST _panos_user=$PANOS_USER _panos_pass=$PANOS_PASS - #Test API Key if found. If the key is invalid, the variable _panos_key will be unset. if [ "$_panos_host" ] && [ "$_panos_key" ]; then _debug "**** Testing API KEY ****" From a9f631f404eaaeaa9a39ba14bb8236a4925db9e8 Mon Sep 17 00:00:00 2001 From: sg1888 Date: Fri, 21 Jul 2023 16:49:20 +0000 Subject: [PATCH 27/55] Added help verbiage for --ecc flag --- acme.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 7a9468fd..d356084c 100755 --- a/acme.sh +++ b/acme.sh @@ -1553,7 +1553,7 @@ createDomainKey() { createCSR() { _info "Creating csr" if [ -z "$1" ]; then - _usage "Usage: $PROJECT_ENTRY --create-csr --domain [--domain ...]" + _usage "Usage: $PROJECT_ENTRY --create-csr --domain [--domain ...] [--ecc]" return fi @@ -6936,7 +6936,8 @@ Parameters: --no-profile Only valid for '--install' command, which means: do not install aliases to user profile. --no-color Do not output color text. --force-color Force output of color text. Useful for non-interactive use with the aha tool for HTML E-Mails. - --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--to-pkcs12' and '--create-csr' + --ecc Specifies use of the ECC cert. Only valid for '--install-cert', '--renew', '--remove ', '--revoke', + '--deploy', '--to-pkcs8', '--to-pkcs12' and '--create-csr'. --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. Runs regardless of whether obtain/renew succeeded or failed. From 2014ca9feb3758999338b31827acbe12c3ca2813 Mon Sep 17 00:00:00 2001 From: Malte Rabenseifner Date: Wed, 26 Jul 2023 15:36:11 +0200 Subject: [PATCH 28/55] Fix the API calls that get the list of domains that PLESK can manage --- dnsapi/dns_pleskxml.sh | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/dnsapi/dns_pleskxml.sh b/dnsapi/dns_pleskxml.sh index 799c374c..9cb0b1be 100644 --- a/dnsapi/dns_pleskxml.sh +++ b/dnsapi/dns_pleskxml.sh @@ -46,6 +46,10 @@ pleskxml_tplt_get_domains="< # Also used to test credentials and URI. # No params. +pleskxml_tplt_get_additional_domains="" +# Get a list of additional domains that PLESK can manage, so we can check root domain + host for acme.sh +# No params. + pleskxml_tplt_get_dns_records="%s" # Get all DNS records for a Plesk domain ID. # PARAM = Plesk domain id to query @@ -375,16 +379,44 @@ _pleskxml_get_root_domain() { return 1 fi - # Generate a crude list of domains known to this Plesk account. + # Generate a crude list of domains known to this Plesk account based on subscriptions. # We convert tags to so it'll flag on a hit with either or fields, # for non-Western character sets. # Output will be one line per known domain, containing 2 tages and a single tag # We don't actually need to check for type, name, *and* id, but it guarantees only usable lines are returned. output="$(_api_response_split "$pleskxml_prettyprint_result" 'result' 'ok' | sed 's///g;s/<\/ascii-name>/<\/name>/g' | grep '' | grep '')" + debug_output="$(printf "$output" | sed -n 's:.*\(.*\).*:\1:p')" + + _debug 'Domains managed by Plesk server are:' + _debug "$debug_output" - _debug 'Domains managed by Plesk server are (ignore the hacked output):' - _debug "$output" + _debug "Querying Plesk server for list of additional managed domains..." + + _call_api "$pleskxml_tplt_get_additional_domains" + if [ "$pleskxml_retcode" -ne 0 ]; then + return 1 + fi + + # Generate a crude list of additional domains known to this Plesk account based on sites. + # We convert tags to so it'll flag on a hit with either or fields, + # for non-Western character sets. + # Output will be one line per known domain, containing 2 tages and a single tag + # We don't actually need to check for type, name, *and* id, but it guarantees only usable lines are returned. + + output_additional="$(_api_response_split "$pleskxml_prettyprint_result" 'result' 'ok' | sed 's///g;s/<\/ascii-name>/<\/name>/g' | grep '' | grep '')" + debug_additional="$(printf "$output_additional" | sed -n 's:.*\(.*\).*:\1:p')" + + _debug 'Additional domains managed by Plesk server are:' + _debug "$debug_additional" + + # Concate the two outputs together. + + output="$(printf "$output $NEWLINE $output_additional")" + debug_output="$(printf "$output" | sed -n 's:.*\(.*\).*:\1:p')" + + _debug 'Domains (including additional) managed by Plesk server are:' + _debug "$debug_output" # loop and test if domain, or any parent domain, is managed by Plesk # Loop until we don't have any '.' in the string we're testing as a candidate Plesk-managed domain From 4d4b6edbc2e59c147b487306604de75e25657f1e Mon Sep 17 00:00:00 2001 From: samuel <53528911+samuel-jimenez@users.noreply.github.com> Date: Wed, 26 Jul 2023 10:29:38 -0500 Subject: [PATCH 29/55] Add DNSExit.com API support --- dnsapi/dns_dnsexit.sh | 185 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 dnsapi/dns_dnsexit.sh diff --git a/dnsapi/dns_dnsexit.sh b/dnsapi/dns_dnsexit.sh new file mode 100644 index 00000000..62d7d757 --- /dev/null +++ b/dnsapi/dns_dnsexit.sh @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +#use dns-01 at DNSExit.com + +#Author: Samuel Jimenez +#Report Bugs here: https://github.com/acmesh-official/acme.sh + +#DNSEXIT_API_KEY=ABCDEFGHIJ0123456789abcdefghij +#DNSEXIT_AUTH_USER=login@email.address +#DNSEXIT_AUTH_PASS=aStrongPassword +DNSEXIT_API_URL="https://api.dnsexit.com/dns/" +DNSEXIT_HOSTS_URL="https://update.dnsexit.com/ipupdate/hosts.jsp" + +######## Public functions ##################### +#Usage: dns_dnsexit_add _acme-challenge.*.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_dnsexit_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using DNSExit.com" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _debug 'Load account auth' + if ! get_account_info; then + return 1 + fi + + _debug 'First detect the root zone' + if ! _get_root "$fulldomain"; then + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if ! _dnsexit_rest "{\"domain\":\"$_domain\",\"add\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":0,\"overwrite\":false}}"; then + _err "$response" + return 1 + fi + + _debug2 _response "$response" + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_dnsexit_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using DNSExit.com" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _debug 'Load account auth' + if ! get_account_info; then + return 1 + fi + + _debug 'First detect the root zone' + if ! _get_root "$fulldomain"; then + _err "$response" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if ! _dnsexit_rest "{\"domain\":\"$_domain\",\"delete\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\"}}"; then + _err "$response" + return 1 + fi + + _debug2 _response "$response" + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=1 + while true; do + _domain=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$_domain" + if [ -z "$_domain" ]; then + return 1 + fi + + _debug login "$DNSEXIT_AUTH_USER" + _debug password "$DNSEXIT_AUTH_PASS" + _debug domain "$_domain" + + _dnsexit_http "login=$DNSEXIT_AUTH_USER&password=$DNSEXIT_AUTH_PASS&domain=$_domain" + + if _contains "$response" "0=$_domain"; then + _sub_domain="$(echo "$fulldomain" | sed "s/\\.$_domain\$//")" + return 0 + else + _debug "Go to next level of $_domain" + fi + i=$(_math "$i" + 1) + done + + return 1 +} + +_dnsexit_rest() { + m=POST + ep="" + data="$1" + _debug _dnsexit_rest "$ep" + _debug data "$data" + + api_key_trimmed=$(echo "$DNSEXIT_API_KEY" | tr -d '"') + + export _H1="apikey: $api_key_trimmed" + export _H2='Content-Type: application/json' + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$DNSEXIT_API_URL/$ep" "" "$m")" + else + response="$(_get "$DNSEXIT_API_URL/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "Error $ep" + return 1 + fi + + _debug2 response "$response" + return 0 +} + +_dnsexit_http() { + m=GET + param="$1" + _debug param "$param" + _debug get "$DNSEXIT_HOSTS_URL?$param" + + response="$(_get "$DNSEXIT_HOSTS_URL?$param")" + + _debug response "$response" + + if [ "$?" != "0" ]; then + _err "Error $param" + return 1 + fi + + _debug2 response "$response" + return 0 +} + +get_account_info() { + + DNSEXIT_API_KEY="${DNSEXIT_API_KEY:-$(_readaccountconf_mutable DNSEXIT_API_KEY)}" + if test -z "$DNSEXIT_API_KEY"; then + DNSEXIT_API_KEY='' + _err 'DNSEXIT_API_KEY was not exported' + return 1 + fi + + _saveaccountconf_mutable DNSEXIT_API_KEY "$DNSEXIT_API_KEY" + + DNSEXIT_AUTH_USER="${DNSEXIT_AUTH_USER:-$(_readaccountconf_mutable DNSEXIT_AUTH_USER)}" + if test -z "$DNSEXIT_AUTH_USER"; then + DNSEXIT_AUTH_USER="" + _err 'DNSEXIT_AUTH_USER was not exported' + return 1 + fi + + _saveaccountconf_mutable DNSEXIT_AUTH_USER "$DNSEXIT_AUTH_USER" + + DNSEXIT_AUTH_PASS="${DNSEXIT_AUTH_PASS:-$(_readaccountconf_mutable DNSEXIT_AUTH_PASS)}" + if test -z "$DNSEXIT_AUTH_PASS"; then + DNSEXIT_AUTH_PASS="" + _err 'DNSEXIT_AUTH_PASS was not exported' + return 1 + fi + + _saveaccountconf_mutable DNSEXIT_AUTH_PASS "$DNSEXIT_AUTH_PASS" + + return 0 +} From c48c8d07de31bbb65a5621d37b9ff6b056e7a8a9 Mon Sep 17 00:00:00 2001 From: Harald Kapper <4014716+hknet@users.noreply.github.com> Date: Thu, 27 Jul 2023 21:49:23 +0200 Subject: [PATCH 30/55] Update dns_kappernet.sh dns update waiting time is reduced now (new backend at kapper.net) --- dnsapi/dns_kappernet.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dnsapi/dns_kappernet.sh b/dnsapi/dns_kappernet.sh index 83a7e5f8..0a8951cb 100644 --- a/dnsapi/dns_kappernet.sh +++ b/dnsapi/dns_kappernet.sh @@ -45,8 +45,8 @@ dns_kappernet_add() { if _kappernet_api GET "action=new&subject=$_domain&data=$data"; then if _contains "$response" "{\"OK\":true"; then - _info "Waiting 120 seconds for DNS to spread the new record" - _sleep 120 + _info "Waiting 1 second for DNS to spread the new record" + _sleep 1 return 0 else _err "Error creating a TXT DNS Record: $fullhostname TXT $txtvalue" From a51025fe8f5c0bacfecb943d997806e55477ce3e Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 29 Jul 2023 15:32:50 +0800 Subject: [PATCH 31/55] fix https://github.com/acmesh-official/acme.sh/issues/3645 --- acme.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 7a9468fd..03c838ac 100755 --- a/acme.sh +++ b/acme.sh @@ -924,7 +924,9 @@ _sed_i() { } _egrep_o() { - if ! egrep -o "$1" 2>/dev/null; then + if _exists egrep; then + egrep -o "$1" 2>/dev/null; + else sed -n 's/.*\('"$1"'\).*/\1/p' fi } From 80006f47300bd0559729a2800ae014475f7499ce Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Sat, 29 Jul 2023 10:26:59 +0200 Subject: [PATCH 32/55] Added bug report url --- dnsapi/dns_artfiles.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_artfiles.sh b/dnsapi/dns_artfiles.sh index faf8c2ae..a762837e 100644 --- a/dnsapi/dns_artfiles.sh +++ b/dnsapi/dns_artfiles.sh @@ -5,7 +5,7 @@ ################################################################################ # Author: Martin Arndt, https://troublezone.net/ # Released: 2022-02-27 -# Issues: https://github.com/acmesh-official/acme.sh/issues/XXXX +# Issues: https://github.com/acmesh-official/acme.sh/issues/4718 ################################################################################ # Usage: # 1. export AF_API_USERNAME='api12345678' From 7f39cdc85660ad3d1fb6b2f6b70cc094fd093e29 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 29 Jul 2023 16:45:49 +0800 Subject: [PATCH 33/55] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 03c838ac..7605c396 100755 --- a/acme.sh +++ b/acme.sh @@ -925,7 +925,7 @@ _sed_i() { _egrep_o() { if _exists egrep; then - egrep -o "$1" 2>/dev/null; + egrep -o "$1" 2>/dev/null else sed -n 's/.*\('"$1"'\).*/\1/p' fi From 3b7be478aa7f5f257397e9cf8cccea3e1a2aa502 Mon Sep 17 00:00:00 2001 From: Malte Rabenseifner Date: Sat, 29 Jul 2023 11:27:33 +0200 Subject: [PATCH 34/55] Fix stuff from tests ShellCheck tests have brought up a couple of issues, that I was not aware of needed to be taken care. This should fix the tests. --- dnsapi/dns_pleskxml.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/dnsapi/dns_pleskxml.sh b/dnsapi/dns_pleskxml.sh index 9cb0b1be..81973e07 100644 --- a/dnsapi/dns_pleskxml.sh +++ b/dnsapi/dns_pleskxml.sh @@ -386,13 +386,13 @@ _pleskxml_get_root_domain() { # We don't actually need to check for type, name, *and* id, but it guarantees only usable lines are returned. output="$(_api_response_split "$pleskxml_prettyprint_result" 'result' 'ok' | sed 's///g;s/<\/ascii-name>/<\/name>/g' | grep '' | grep '')" - debug_output="$(printf "$output" | sed -n 's:.*\(.*\).*:\1:p')" - + debug_output="$(printf "%s" "$output" | sed -n 's:.*\(.*\).*:\1:p')" + _debug 'Domains managed by Plesk server are:' - _debug "$debug_output" + _debug "$debug_output" _debug "Querying Plesk server for list of additional managed domains..." - + _call_api "$pleskxml_tplt_get_additional_domains" if [ "$pleskxml_retcode" -ne 0 ]; then return 1 @@ -405,18 +405,18 @@ _pleskxml_get_root_domain() { # We don't actually need to check for type, name, *and* id, but it guarantees only usable lines are returned. output_additional="$(_api_response_split "$pleskxml_prettyprint_result" 'result' 'ok' | sed 's///g;s/<\/ascii-name>/<\/name>/g' | grep '' | grep '')" - debug_additional="$(printf "$output_additional" | sed -n 's:.*\(.*\).*:\1:p')" + debug_additional="$(printf "%s" "$output_additional" | sed -n 's:.*\(.*\).*:\1:p')" _debug 'Additional domains managed by Plesk server are:' _debug "$debug_additional" - + # Concate the two outputs together. - - output="$(printf "$output $NEWLINE $output_additional")" - debug_output="$(printf "$output" | sed -n 's:.*\(.*\).*:\1:p')" - + + output="$(printf "%s" "$output $NEWLINE $output_additional")" + debug_output="$(printf "%s" "$output" | sed -n 's:.*\(.*\).*:\1:p')" + _debug 'Domains (including additional) managed by Plesk server are:' - _debug "$debug_output" + _debug "$debug_output" # loop and test if domain, or any parent domain, is managed by Plesk # Loop until we don't have any '.' in the string we're testing as a candidate Plesk-managed domain From a7f3d413ef81782a43cf568ab7a136ffb7e9e5e5 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 29 Jul 2023 22:32:30 +0800 Subject: [PATCH 35/55] fix for solaris --- acme.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 7605c396..c79cadfc 100755 --- a/acme.sh +++ b/acme.sh @@ -2103,9 +2103,20 @@ _head_n() { } _tail_n() { - if ! tail -n "$1" 2>/dev/null; then + if _is_solaris; then #fix for solaris tail -"$1" + else + tail -n "$1" + fi +} + +_tail_c() { + if _is_solaris; then + #fix for solaris + tail -"$1"c + else + tail -c "$1" fi } @@ -2280,7 +2291,7 @@ _setopt() { if [ ! -f "$__conf" ]; then touch "$__conf" fi - if [ -n "$(tail -c1 <"$__conf")" ]; then + if [ -n "$(_tail_c 1 <"$__conf")" ]; then echo >>"$__conf" fi From 6db8ae451ab3263570bdb2eb3b33d10c91f289c5 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 29 Jul 2023 23:17:20 +0800 Subject: [PATCH 36/55] fix for solaris --- acme.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index c79cadfc..3c9ba003 100755 --- a/acme.sh +++ b/acme.sh @@ -924,10 +924,10 @@ _sed_i() { } _egrep_o() { - if _exists egrep; then - egrep -o "$1" 2>/dev/null - else + if _is_solaris; then sed -n 's/.*\('"$1"'\).*/\1/p' + else + egrep -o "$1" fi } From 15ee036db17d13a8ec75275e0b7ef729a79dc9f2 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 29 Jul 2023 23:30:44 +0800 Subject: [PATCH 37/55] fix for solaris --- acme.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/acme.sh b/acme.sh index 3c9ba003..75efde4c 100755 --- a/acme.sh +++ b/acme.sh @@ -923,11 +923,17 @@ _sed_i() { fi } +if [ "$(echo abc | egrep -o b 2>/dev/null)" = "b" ]; then + __USE_EGREP=1 +else + __USE_EGREP="" +fi + _egrep_o() { - if _is_solaris; then - sed -n 's/.*\('"$1"'\).*/\1/p' - else + if [ "$__USE_EGREP" ]; then egrep -o "$1" + else + sed -n 's/.*\('"$1"'\).*/\1/p' fi } From b6f62ac446ab9ff78f4a90c4330dc314678545c9 Mon Sep 17 00:00:00 2001 From: neil Date: Sun, 30 Jul 2023 10:58:22 +0800 Subject: [PATCH 38/55] fix for curl bugs nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation see https://bugs.launchpad.net/ubuntu/+source/curl/+bug/2018342 --- .github/workflows/DragonFlyBSD.yml | 2 +- .github/workflows/OpenBSD.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/DragonFlyBSD.yml b/.github/workflows/DragonFlyBSD.yml index 6daa9be4..5a0d81ba 100644 --- a/.github/workflows/DragonFlyBSD.yml +++ b/.github/workflows/DragonFlyBSD.yml @@ -62,7 +62,7 @@ jobs: nat: | "8080": "80" prepare: | - pkg install -y curl socat + pkg install -y curl socat libnghttp2 usesh: true run: | cd ../acmetest \ diff --git a/.github/workflows/OpenBSD.yml b/.github/workflows/OpenBSD.yml index 7746645a..745a9408 100644 --- a/.github/workflows/OpenBSD.yml +++ b/.github/workflows/OpenBSD.yml @@ -66,7 +66,7 @@ jobs: envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET' nat: | "8080": "80" - prepare: pkg_add socat curl wget + prepare: pkg_add socat curl wget libnghttp2 usesh: true copyback: false run: | From d52b38777aaf19bc49ef6edd5d23546ddd3a4f03 Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Wed, 9 Aug 2023 19:52:37 +0200 Subject: [PATCH 39/55] Fix Auth API access for DSM 6 --- deploy/synology_dsm.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/deploy/synology_dsm.sh b/deploy/synology_dsm.sh index 7398b350..ba35d784 100644 --- a/deploy/synology_dsm.sh +++ b/deploy/synology_dsm.sh @@ -91,8 +91,10 @@ synology_dsm_deploy() { _debug "Getting API version" response=$(_get "$_base_url/webapi/query.cgi?api=SYNO.API.Info&version=1&method=query&query=SYNO.API.Auth") + api_path=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"path" *: *"\([0-9]*\)".*/\1/p') api_version=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"maxVersion" *: *\([0-9]*\).*/\1/p') _debug3 response "$response" + _debug3 api_path "$api_path" _debug3 api_version "$api_version" # Login, get the session ID & SynoToken from JSON @@ -133,12 +135,12 @@ synology_dsm_deploy() { [ -n "${SYNO_Device_Name}" ] || SYNO_Device_Name="CertRenewal" fi - response=$(_get "$_base_url/webapi/entry.cgi?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&otp_code=$otp_code&enable_syno_token=yes&enable_device_token=yes&device_name=$SYNO_Device_Name") + response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&otp_code=$otp_code&enable_syno_token=yes&enable_device_token=yes&device_name=$SYNO_Device_Name") _debug3 response "$response" SYNO_Device_ID=$(echo "$response" | grep "device_id" | sed -n 's/.*"device_id" *: *"\([^"]*\).*/\1/p') _secure_debug2 SYNO_Device_ID "$SYNO_Device_ID" else - response=$(_get "$_base_url/webapi/entry.cgi?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&device_name=$SYNO_Device_Name&device_id=$SYNO_Device_ID") + response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&device_name=$SYNO_Device_Name&device_id=$SYNO_Device_ID") _debug3 response "$response" fi From b793dbf977dbf5d6b6829d185e0b2a0fa130941a Mon Sep 17 00:00:00 2001 From: Martin Arndt <5111490+Eagle3386@users.noreply.github.com> Date: Fri, 11 Aug 2023 17:55:45 +0200 Subject: [PATCH 40/55] Fix device ID property name for DSM 6 --- deploy/synology_dsm.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/deploy/synology_dsm.sh b/deploy/synology_dsm.sh index ba35d784..21c7ac9b 100644 --- a/deploy/synology_dsm.sh +++ b/deploy/synology_dsm.sh @@ -136,8 +136,11 @@ synology_dsm_deploy() { fi response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&otp_code=$otp_code&enable_syno_token=yes&enable_device_token=yes&device_name=$SYNO_Device_Name") - _debug3 response "$response" - SYNO_Device_ID=$(echo "$response" | grep "device_id" | sed -n 's/.*"device_id" *: *"\([^"]*\).*/\1/p') + _secure_debug3 response "$response" + + id_property='device_id' + [ "${api_version}" -gt '6' ] || id_property='did' + SYNO_Device_ID=$(echo "$response" | grep "$id_property" | sed -n 's/.*"'$id_property'" *: *"\([^"]*\).*/\1/p') _secure_debug2 SYNO_Device_ID "$SYNO_Device_ID" else response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&device_name=$SYNO_Device_Name&device_id=$SYNO_Device_ID") From 8d00f489cd6072d562dce05e7a43a5bdb0877113 Mon Sep 17 00:00:00 2001 From: Vito <35035879+vitoyucepi@users.noreply.github.com> Date: Sun, 20 Aug 2023 20:05:45 +0300 Subject: [PATCH 41/55] Remove excessive full stop from help --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 07aef029..70f1daac 100755 --- a/acme.sh +++ b/acme.sh @@ -6925,7 +6925,7 @@ Parameters: These parameters are to install the cert to nginx/apache or any other server after issue/renew a cert: - --cert-file Path to copy the cert file to after issue/renew.. + --cert-file Path to copy the cert file to after issue/renew. --key-file Path to copy the key file to after issue/renew. --ca-file Path to copy the intermediate cert file to after issue/renew. --fullchain-file Path to copy the fullchain cert file to after issue/renew. From 13d31ecb7f195f623a9a4deff9c2eb3fc6aecaeb Mon Sep 17 00:00:00 2001 From: Nirjas Jakilim Date: Mon, 21 Aug 2023 12:28:50 +0600 Subject: [PATCH 42/55] fixed regex for nginx conf path Fixed the regex for nginx path configuration to fix grep: unrecognized option error --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 75efde4c..8c662486 100755 --- a/acme.sh +++ b/acme.sh @@ -3130,7 +3130,7 @@ _setNginx() { _err "nginx command is not found." return 1 fi - NGINX_CONF="$(nginx -V 2>&1 | _egrep_o "--conf-path=[^ ]* " | tr -d " ")" + 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" From 9143cd1485a4a0220897124fec78eb2ec45f81ec Mon Sep 17 00:00:00 2001 From: glocknerc <65351984+glocknerc@users.noreply.github.com> Date: Wed, 23 Aug 2023 14:07:07 +0200 Subject: [PATCH 43/55] Change grep to be case-insensitive when looking for Set-Cookie header since INWX change casing to lowercase --- dnsapi/dns_inwx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index ba789da9..e483c0e8 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -194,7 +194,7 @@ _inwx_login() { response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - INWX_Cookie=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')") + INWX_Cookie=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep -i "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')") _H1=$INWX_Cookie export _H1 export INWX_Cookie From 9b0b5bce9f79672dff5eb80dbb74a0ec4c88986f Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 28 Aug 2023 15:30:26 +0200 Subject: [PATCH 44/55] inwx: Be case insensitive while searching for the cookie. At least since 2023-08-25 the cookie is set via `set-cookie' instead the expecting `Set-Cookie' string. A month earlier it was working. Ignore the case while matching the cookie. Fixes: #4763 Signed-off-by: Sebastian Andrzej Siewior --- dnsapi/dns_inwx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_inwx.sh b/dnsapi/dns_inwx.sh index ba789da9..e483c0e8 100755 --- a/dnsapi/dns_inwx.sh +++ b/dnsapi/dns_inwx.sh @@ -194,7 +194,7 @@ _inwx_login() { response="$(_post "$xml_content" "$INWX_Api" "" "POST")" - INWX_Cookie=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')") + INWX_Cookie=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep -i "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')") _H1=$INWX_Cookie export _H1 export INWX_Cookie From 089d35708b99fe326660c8d95ed30b5040532d40 Mon Sep 17 00:00:00 2001 From: KincaidYang <91786638+KincaidYang@users.noreply.github.com> Date: Sat, 2 Sep 2023 14:31:17 +0800 Subject: [PATCH 45/55] fix for curl bugs nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation see https://bugs.launchpad.net/ubuntu/+source/curl/+bug/2018342 https://github.com/acmesh-official/acme.sh/commit/b6f62ac446ab9ff78f4a90c4330dc314678545c9 https://github.com/acmesh-official/acme.sh/issues/4775 --- .github/workflows/DNS.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/DNS.yml b/.github/workflows/DNS.yml index 615e5d8b..a13cb51c 100644 --- a/.github/workflows/DNS.yml +++ b/.github/workflows/DNS.yml @@ -332,7 +332,7 @@ jobs: with: envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}' prepare: | - pkg_add curl socat + pkg_add curl socat libnghttp2 usesh: true copyback: false run: | @@ -384,7 +384,7 @@ jobs: with: envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}' prepare: | - pkg install -y curl socat + pkg install -y curl socat libnghttp2 usesh: true copyback: false run: | From 29a2920a2c585488ba1f81f9d459d86aab951f9e Mon Sep 17 00:00:00 2001 From: KincaidYang <91786638+KincaidYang@users.noreply.github.com> Date: Sat, 2 Sep 2023 14:49:43 +0800 Subject: [PATCH 46/55] Add dns_tencent.sh Adapt to Tencent Cloud (DNSPod) API 3.0 --- dnsapi/dns_tencent.sh | 201 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 dnsapi/dns_tencent.sh diff --git a/dnsapi/dns_tencent.sh b/dnsapi/dns_tencent.sh new file mode 100644 index 00000000..30e33f03 --- /dev/null +++ b/dnsapi/dns_tencent.sh @@ -0,0 +1,201 @@ +#!/usr/bin/env sh +set -x +Tencent_API="https://dnspod.tencentcloudapi.com" + +#Tencent_SecretId="AKIDz8krbsJ5yKBZQpn74WFkmLPx3gnPhESA" +#Tencent_SecretKey="Gu5t9xGARNpq86cd98joQYCN3Cozk1qA" + +#Usage: dns_tencent_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_tencent_add() { + fulldomain=$1 + txtvalue=$2 + + Tencent_SecretId="${Tencent_SecretId:-$(_readaccountconf_mutable Tencent_SecretId)}" + Tencent_SecretKey="${Tencent_SecretKey:-$(_readaccountconf_mutable Tencent_SecretKey)}" + if [ -z "$Tencent_SecretId" ] || [ -z "$Tencent_SecretKey" ]; then + Tencent_SecretId="" + Tencent_SecretKey="" + _err "You don't specify tencent api SecretId and SecretKey yet." + return 1 + fi + + #save the api SecretId and SecretKey to the account conf file. + _saveaccountconf_mutable Tencent_SecretId "$Tencent_SecretId" + _saveaccountconf_mutable Tencent_SecretKey "$Tencent_SecretKey" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + return 1 + fi + + _debug "Add record" + _add_record_query "$_domain" "$_sub_domain" "$txtvalue" && _tencent_rest "CreateRecord" +} + +dns_tencent_rm() { + fulldomain=$1 + txtvalue=$2 + Tencent_SecretId="${Tencent_SecretId:-$(_readaccountconf_mutable Tencent_SecretId)}" + Tencent_SecretKey="${Tencent_SecretKey:-$(_readaccountconf_mutable Tencent_SecretKey)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + return 1 + fi + + _debug "Get record list" + sleep 30 + _check_exist_query "$_domain" "$_sub_domain" "$txtvalue" && _tencent_rest "DescribeRecordFilterList" + + record_id="$(echo "$response" | _egrep_o "\"RecordId\":\s*[0-9]+" | _egrep_o "[0-9]+")" + _debug2 record_id "$record_id" + + if [ -z "$record_id" ]; then + _debug "record not found, skip" + else + _debug "Delete record" + _delete_record_query "$record_id" && _tencent_rest "DeleteRecord" + fi +} + +#################### 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 ! _tencent_rest "DescribeRecordList" "ignore"; then + return 1 + fi + + if _contains "$response" "\"TotalCount\":"; 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 +} + +_tencent_rest() { + action=$1 + service="dnspod" + payload="${query}" + timestamp=$(date -u +%s) + + token=$(tencent_signature_v3 $service "$action" "$payload" "$timestamp") + version="2021-03-23" + + if ! response="$(tencent_api_request $service $version "$action" "$payload" "$timestamp")"; then + _err "Error <$1>" + return 1 + fi + + _debug2 response "$response" + if [ -z "$2" ]; then + message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" + if [ "$message" ]; then + _err "$message" + return 1 + fi + fi +} + +_add_record_query() { + query="{\"Domain\":\"$1\",\"SubDomain\":\"$2\",\"RecordType\":\"TXT\",\"RecordLineId\":\"0\",\"RecordLine\":\"0\",\"Value\":\"$3\",\"TTL\":600}" +} + +_describe_records_query() { + query="{\"Domain\":\"$1\",\"Limit\":3000}" +} + +_delete_record_query() { + query="{\"Domain\":\"$_domain\",\"RecordId\":$1}" +} + +_check_exist_query() { + _domain="$1" + _subdomain="$2" + _value="$3" + query="{\"Domain\":\"$_domain\",\"SubDomain\":\"$_subdomain\",\"RecordValue\":\"$_value\"}" +} + +# shell client for tencent cloud api v3 | @author: rehiy + +tencent_sha256() { + printf %b "$@" | openssl dgst -sha256 -hex | sed 's/^.* //' +} + +tencent_hmac_sha256() { + k=$1 + shift + printf %b "$@" | openssl dgst -sha256 -hmac "$k" | sed 's/^.* //' +} + +tencent_hmac_sha256_hexkey() { + k=$1 + shift + printf %b "$@" | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$k" | sed 's/^.* //' +} + +tencent_signature_v3() { + service=$1 + action=$(echo "$2" | tr '[:upper:]' '[:lower:]') + payload=${3:-'{}'} + timestamp=${4:-$(date +%s)} + + domain="$service.tencentcloudapi.com" + secretId=${Tencent_SecretId:-'tencent-cloud-secret-id'} + secretKey=${Tencent_SecretKey:-'tencent-cloud-secret-key'} + + algorithm='TC3-HMAC-SHA256' + date=$(date -u -d "@$timestamp" +%Y-%m-%d 2>/dev/null) + [ -z "$date" ] && date=$(date -u -r "$timestamp" +%Y-%m-%d) + + canonicalUri='/' + canonicalQuery='' + canonicalHeaders="content-type:application/json\nhost:$domain\nx-tc-action:$action\n" + + signedHeaders='content-type;host;x-tc-action' + canonicalRequest="POST\n$canonicalUri\n$canonicalQuery\n$canonicalHeaders\n$signedHeaders\n$(tencent_sha256 "$payload")" + + credentialScope="$date/$service/tc3_request" + stringToSign="$algorithm\n$timestamp\n$credentialScope\n$(tencent_sha256 "$canonicalRequest")" + + secretDate=$(tencent_hmac_sha256 "TC3$secretKey" "$date") + secretService=$(tencent_hmac_sha256_hexkey "$secretDate" "$service") + secretSigning=$(tencent_hmac_sha256_hexkey "$secretService" 'tc3_request') + signature=$(tencent_hmac_sha256_hexkey "$secretSigning" "$stringToSign") + + echo "$algorithm Credential=$secretId/$credentialScope, SignedHeaders=$signedHeaders, Signature=$signature" +} + +tencent_api_request() { + service=$1 + version=$2 + action=$3 + payload=${4:-'{}'} + timestamp=${5:-$(date +%s)} + + token=$(tencent_signature_v3 "$service" "$action" "$payload" "$timestamp") + + _H1="Content-Type: application/json" + _H2="Authorization: $token" + _H3="X-TC-Version: $version" + _H4="X-TC-Timestamp: $timestamp" + _H5="X-TC-Action: $action" + + _post "$payload" "$Tencent_API" "" "POST" "application/json" +} From e5b76ed4c4326c6ce039121c1ed78908aa450288 Mon Sep 17 00:00:00 2001 From: KincaidYang <91786638+KincaidYang@users.noreply.github.com> Date: Sat, 2 Sep 2023 15:13:37 +0800 Subject: [PATCH 47/55] Delete dnsapi/dns_tencent.sh --- dnsapi/dns_tencent.sh | 201 ------------------------------------------ 1 file changed, 201 deletions(-) delete mode 100644 dnsapi/dns_tencent.sh diff --git a/dnsapi/dns_tencent.sh b/dnsapi/dns_tencent.sh deleted file mode 100644 index 30e33f03..00000000 --- a/dnsapi/dns_tencent.sh +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/env sh -set -x -Tencent_API="https://dnspod.tencentcloudapi.com" - -#Tencent_SecretId="AKIDz8krbsJ5yKBZQpn74WFkmLPx3gnPhESA" -#Tencent_SecretKey="Gu5t9xGARNpq86cd98joQYCN3Cozk1qA" - -#Usage: dns_tencent_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" -dns_tencent_add() { - fulldomain=$1 - txtvalue=$2 - - Tencent_SecretId="${Tencent_SecretId:-$(_readaccountconf_mutable Tencent_SecretId)}" - Tencent_SecretKey="${Tencent_SecretKey:-$(_readaccountconf_mutable Tencent_SecretKey)}" - if [ -z "$Tencent_SecretId" ] || [ -z "$Tencent_SecretKey" ]; then - Tencent_SecretId="" - Tencent_SecretKey="" - _err "You don't specify tencent api SecretId and SecretKey yet." - return 1 - fi - - #save the api SecretId and SecretKey to the account conf file. - _saveaccountconf_mutable Tencent_SecretId "$Tencent_SecretId" - _saveaccountconf_mutable Tencent_SecretKey "$Tencent_SecretKey" - - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - return 1 - fi - - _debug "Add record" - _add_record_query "$_domain" "$_sub_domain" "$txtvalue" && _tencent_rest "CreateRecord" -} - -dns_tencent_rm() { - fulldomain=$1 - txtvalue=$2 - Tencent_SecretId="${Tencent_SecretId:-$(_readaccountconf_mutable Tencent_SecretId)}" - Tencent_SecretKey="${Tencent_SecretKey:-$(_readaccountconf_mutable Tencent_SecretKey)}" - - _debug "First detect the root zone" - if ! _get_root "$fulldomain"; then - return 1 - fi - - _debug "Get record list" - sleep 30 - _check_exist_query "$_domain" "$_sub_domain" "$txtvalue" && _tencent_rest "DescribeRecordFilterList" - - record_id="$(echo "$response" | _egrep_o "\"RecordId\":\s*[0-9]+" | _egrep_o "[0-9]+")" - _debug2 record_id "$record_id" - - if [ -z "$record_id" ]; then - _debug "record not found, skip" - else - _debug "Delete record" - _delete_record_query "$record_id" && _tencent_rest "DeleteRecord" - fi -} - -#################### 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 ! _tencent_rest "DescribeRecordList" "ignore"; then - return 1 - fi - - if _contains "$response" "\"TotalCount\":"; 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 -} - -_tencent_rest() { - action=$1 - service="dnspod" - payload="${query}" - timestamp=$(date -u +%s) - - token=$(tencent_signature_v3 $service "$action" "$payload" "$timestamp") - version="2021-03-23" - - if ! response="$(tencent_api_request $service $version "$action" "$payload" "$timestamp")"; then - _err "Error <$1>" - return 1 - fi - - _debug2 response "$response" - if [ -z "$2" ]; then - message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" - if [ "$message" ]; then - _err "$message" - return 1 - fi - fi -} - -_add_record_query() { - query="{\"Domain\":\"$1\",\"SubDomain\":\"$2\",\"RecordType\":\"TXT\",\"RecordLineId\":\"0\",\"RecordLine\":\"0\",\"Value\":\"$3\",\"TTL\":600}" -} - -_describe_records_query() { - query="{\"Domain\":\"$1\",\"Limit\":3000}" -} - -_delete_record_query() { - query="{\"Domain\":\"$_domain\",\"RecordId\":$1}" -} - -_check_exist_query() { - _domain="$1" - _subdomain="$2" - _value="$3" - query="{\"Domain\":\"$_domain\",\"SubDomain\":\"$_subdomain\",\"RecordValue\":\"$_value\"}" -} - -# shell client for tencent cloud api v3 | @author: rehiy - -tencent_sha256() { - printf %b "$@" | openssl dgst -sha256 -hex | sed 's/^.* //' -} - -tencent_hmac_sha256() { - k=$1 - shift - printf %b "$@" | openssl dgst -sha256 -hmac "$k" | sed 's/^.* //' -} - -tencent_hmac_sha256_hexkey() { - k=$1 - shift - printf %b "$@" | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$k" | sed 's/^.* //' -} - -tencent_signature_v3() { - service=$1 - action=$(echo "$2" | tr '[:upper:]' '[:lower:]') - payload=${3:-'{}'} - timestamp=${4:-$(date +%s)} - - domain="$service.tencentcloudapi.com" - secretId=${Tencent_SecretId:-'tencent-cloud-secret-id'} - secretKey=${Tencent_SecretKey:-'tencent-cloud-secret-key'} - - algorithm='TC3-HMAC-SHA256' - date=$(date -u -d "@$timestamp" +%Y-%m-%d 2>/dev/null) - [ -z "$date" ] && date=$(date -u -r "$timestamp" +%Y-%m-%d) - - canonicalUri='/' - canonicalQuery='' - canonicalHeaders="content-type:application/json\nhost:$domain\nx-tc-action:$action\n" - - signedHeaders='content-type;host;x-tc-action' - canonicalRequest="POST\n$canonicalUri\n$canonicalQuery\n$canonicalHeaders\n$signedHeaders\n$(tencent_sha256 "$payload")" - - credentialScope="$date/$service/tc3_request" - stringToSign="$algorithm\n$timestamp\n$credentialScope\n$(tencent_sha256 "$canonicalRequest")" - - secretDate=$(tencent_hmac_sha256 "TC3$secretKey" "$date") - secretService=$(tencent_hmac_sha256_hexkey "$secretDate" "$service") - secretSigning=$(tencent_hmac_sha256_hexkey "$secretService" 'tc3_request') - signature=$(tencent_hmac_sha256_hexkey "$secretSigning" "$stringToSign") - - echo "$algorithm Credential=$secretId/$credentialScope, SignedHeaders=$signedHeaders, Signature=$signature" -} - -tencent_api_request() { - service=$1 - version=$2 - action=$3 - payload=${4:-'{}'} - timestamp=${5:-$(date +%s)} - - token=$(tencent_signature_v3 "$service" "$action" "$payload" "$timestamp") - - _H1="Content-Type: application/json" - _H2="Authorization: $token" - _H3="X-TC-Version: $version" - _H4="X-TC-Timestamp: $timestamp" - _H5="X-TC-Action: $action" - - _post "$payload" "$Tencent_API" "" "POST" "application/json" -} From b32d22731b00b723600e0de9f6b9fceb60952f37 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 2 Sep 2023 15:32:12 +0800 Subject: [PATCH 48/55] remove --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 73ff3321..717ecf5f 100644 --- a/README.md +++ b/README.md @@ -506,10 +506,6 @@ Support this project with your organization. Your logo will show up here with a -#### Sponsors - -[![quantumca-acmesh-logo](https://user-images.githubusercontent.com/8305679/183255712-634ee1db-bb61-4c03-bca0-bacce99e078c.svg)](https://www.quantumca.com.cn/?__utm_source=acmesh-donation) - # 19. License & Others From 8bdcd224862af85d99e682844e71122772c3eba7 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 2 Sep 2023 15:44:45 +0800 Subject: [PATCH 49/55] fix https://github.com/acmesh-official/acme.sh/issues/4746 --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 70f1daac..a8256609 100755 --- a/acme.sh +++ b/acme.sh @@ -931,7 +931,7 @@ fi _egrep_o() { if [ "$__USE_EGREP" ]; then - egrep -o "$1" + egrep -o -- "$1" else sed -n 's/.*\('"$1"'\).*/\1/p' fi From 04946e992eb60a3cc85b4c9b0e0fe9a577ac1e5e Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 2 Sep 2023 17:15:17 +0800 Subject: [PATCH 50/55] change the default debug level to 2. --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 92faeb5e..7b61b109 100755 --- a/acme.sh +++ b/acme.sh @@ -107,7 +107,7 @@ 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_DEFAULT=$DEBUG_LEVEL_2 DEBUG_LEVEL_NONE=0 DOH_CLOUDFLARE=1 @@ -6899,7 +6899,7 @@ Parameters: -f, --force Force install, force cert renewal or override sudo restrictions. --staging, --test Use staging server, for testing. - --debug [0|1|2|3] Output debug info. Defaults to 1 if argument is omitted. + --debug [0|1|2|3] Output debug info. Defaults to $DEBUG_LEVEL_DEFAULT if argument is omitted. --output-insecure Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for security. -w, --webroot Specifies the web root folder for web root mode. From c18364c75549e840a9db0025fc86947f4fdab114 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 2 Sep 2023 17:18:12 +0800 Subject: [PATCH 51/55] change default log level to 2 --- acme.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme.sh b/acme.sh index 7b61b109..4fab21d2 100755 --- a/acme.sh +++ b/acme.sh @@ -102,7 +102,7 @@ ECC_SUFFIX="${ECC_SEP}ecc" LOG_LEVEL_1=1 LOG_LEVEL_2=2 LOG_LEVEL_3=3 -DEFAULT_LOG_LEVEL="$LOG_LEVEL_1" +DEFAULT_LOG_LEVEL="$LOG_LEVEL_2" DEBUG_LEVEL_1=1 DEBUG_LEVEL_2=2 @@ -6917,7 +6917,7 @@ Parameters: -k, --keylength Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384, ec-521. -ak, --accountkeylength Specifies the account key length: 2048, 3072, 4096 --log [file] Specifies the log file. Defaults to \"$DEFAULT_LOG_FILE\" if argument is omitted. - --log-level <1|2> Specifies the log level, default is 1. + --log-level <1|2> Specifies the log level, default is $DEFAULT_LOG_LEVEL. --syslog <0|3|6|7> Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug. --eab-kid Key Identifier for External Account Binding. --eab-hmac-key HMAC key for External Account Binding. From eed8a7f0788190d44e6a603bd49eb96c508fdb3c Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 2 Sep 2023 17:27:21 +0800 Subject: [PATCH 52/55] add more debug code https://github.com/acmesh-official/acme.sh/issues/4768 --- acme.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acme.sh b/acme.sh index 4fab21d2..54dfa9a5 100755 --- a/acme.sh +++ b/acme.sh @@ -5015,9 +5015,9 @@ $_authorizations_map" errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)" _debug2 errordetail "$errordetail" if [ "$errordetail" ]; then - _err "$d:Verify error:$errordetail" + _err "Invalid status, $d:Verify error detail:$errordetail" else - _err "$d:Verify error:$error" + _err "Invalid status, $d:Verify error:$error" fi if [ "$DEBUG" ]; then if [ "$vtype" = "$VTYPE_HTTP" ]; then @@ -5044,7 +5044,7 @@ $_authorizations_map" elif _contains "$status" "processing"; then _info "Processing, The CA is processing your order, please just wait. ($waittimes/$MAX_RETRY_TIMES)" else - _err "$d:Verify error:$response" + _err "Unknown status: $status, $d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup _on_issue_err "$_post_hook" "$vlist" @@ -5057,7 +5057,7 @@ $_authorizations_map" _send_signed_request "$_authz_url" if [ "$?" != "0" ]; then - _err "$d:Verify error:$response" + _err "Invalid code, $d:Verify error:$response" _clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearup _on_issue_err "$_post_hook" "$vlist" From 87dc4fe388244663055cea068b23c97632561544 Mon Sep 17 00:00:00 2001 From: KincaidYang <91786638+KincaidYang@users.noreply.github.com> Date: Sat, 2 Sep 2023 18:23:14 +0800 Subject: [PATCH 53/55] =?UTF-8?q?fix=20for=20curl=20bugs=20nghttp2=5Foptio?= =?UTF-8?q?n=5Fset=5Fno=5Frfc9113=5Fleading=5Fand=5Ftrailing=5F=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In #4776, I mistakenly added libnghttp2 to NetBsd, and now it has been corrected and added to OpenBsd --- .github/workflows/DNS.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/DNS.yml b/.github/workflows/DNS.yml index a13cb51c..8bae3520 100644 --- a/.github/workflows/DNS.yml +++ b/.github/workflows/DNS.yml @@ -280,7 +280,7 @@ jobs: - uses: vmactions/openbsd-vm@v0 with: envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}' - prepare: pkg_add socat curl + prepare: pkg_add socat curl libnghttp2 usesh: true copyback: false run: | @@ -332,7 +332,7 @@ jobs: with: envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}' prepare: | - pkg_add curl socat libnghttp2 + pkg_add curl socat usesh: true copyback: false run: | From 09b41aa66711777b90c8d6200b825330ffee2e09 Mon Sep 17 00:00:00 2001 From: KincaidYang <91786638+KincaidYang@users.noreply.github.com> Date: Sat, 2 Sep 2023 18:38:51 +0800 Subject: [PATCH 54/55] fix for nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation In #4776, I mistakenly added libnghttp2 to NetBSD, now for correction. --- .github/workflows/DNS.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/DNS.yml b/.github/workflows/DNS.yml index 8bae3520..507755c9 100644 --- a/.github/workflows/DNS.yml +++ b/.github/workflows/DNS.yml @@ -280,7 +280,7 @@ jobs: - uses: vmactions/openbsd-vm@v0 with: envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}' - prepare: pkg_add socat curl libnghttp2 + prepare: pkg_add socat curl usesh: true copyback: false run: | From 27b1dd04c4d240d368d79216e84debbaeed813ae Mon Sep 17 00:00:00 2001 From: LJea Date: Sun, 3 Sep 2023 01:02:16 +0900 Subject: [PATCH 55/55] improve the compatibility Fixed an issue where some embedded devices could not obtain nanoseconds resulting in abnormal parameter coding --- dnsapi/dns_ali.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_ali.sh b/dnsapi/dns_ali.sh index c2105672..c69839dc 100755 --- a/dnsapi/dns_ali.sh +++ b/dnsapi/dns_ali.sh @@ -117,7 +117,7 @@ _ali_urlencode() { _ali_nonce() { #_head_n 1