From dbe726d9fb5dc88a29c8d2f515b351f88446eba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sat, 2 Jul 2022 21:51:03 +0200 Subject: [PATCH 01/96] Add FTL communication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 186 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 155 insertions(+), 31 deletions(-) diff --git a/padd.sh b/padd.sh index 5cb68c4..5552f07 100755 --- a/padd.sh +++ b/padd.sh @@ -14,7 +14,7 @@ LC_NUMERIC=C ############################################ VARIABLES ############################################# # VERSION -padd_version="v3.8.0" +padd_version="v4.0.0" # LastChecks LastCheckVersionInformation=$(date +%s) @@ -103,6 +103,98 @@ padd_logo_retro_1="${bold_text} ${yellow_text}_${green_text}_ ${blue_text}_ padd_logo_retro_2="${bold_text}${yellow_text}|${green_text}_${blue_text}_${cyan_text}) ${red_text}/${yellow_text}\\ ${blue_text}| ${red_text}\\${yellow_text}| ${cyan_text}\\ ${reset_text}" padd_logo_retro_3="${bold_text}${green_text}| ${red_text}/${yellow_text}-${green_text}-${blue_text}\\${cyan_text}|${magenta_text}_${red_text}_${yellow_text}/${green_text}|${blue_text}_${cyan_text}_${magenta_text}/ ${reset_text}" +############################################# FTL ################################################## + +ConstructAPI() { + # If no arguments were supplied set them to default + if [ -z "${URL}" ]; then + URL=pi.hole + fi + if [ -z "${PORT}" ]; then + PORT=8080 + fi + if [ -z "${APIPATH}" ]; then + APIPATH=api + fi +} + +Authenthication() { + # Try to authenticate + ChallengeResponse + + while [ "${validSession}" = false ]; do + echo "Authentication with FTL server failed." + + # no password was supplied as argument + if [ -z "${password}" ]; then + echo "Please enter your Pi-hole password:" + else + echo "Wrong Pi-hole password supplied, please enter the correct password:" + fi + + # POSIX's `read` does not support `-s` option (suppressing the input) + # this workaround changes the terminal characteristics to not echo input and later rests this option + # credits https://stackoverflow.com/a/4316765 + + stty_orig=$(stty -g) + stty -echo + read -r password + stty "${stty_orig}" + echo "" + + # Try to authenticate again + ChallengeResponse + done + + # Loop exited, authentication was successful + echo "Authentication with FTL server successful." + +} + +DeleteSession() { + + # Try to delte the session. Omitt the output, but get the http status code + deleteResponse=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE http://${URL}:${PORT}/${APIPATH}/auth -H "Accept: application/json" -H "sid: ${SID}") + + case "${deleteResponse}" in + "200") echo "A session that was not created cannot be deleted (e.g., empty API password).";; + "401") echo "Logout attempt without a valid session. Unauthorized!";; + "410") echo "Session deleted successfully";; + esac; + +} + +ChallengeResponse() { + # Challenge-response authentication + + # Compute password hash from user password + # Compute password hash twice to avoid rainbow table vulnerability + hash1=$(printf "%b" "$password" | sha256sum | sed 's/\s.*$//') + pwhash=$(printf "%b" "$hash1" | sha256sum | sed 's/\s.*$//') + + + # Get challenge from FTL + # Calculate response based on challenge and password hash + # Send response & get session response + challenge="$(curl --silent -X GET http://${URL}:${PORT}/${APIPATH}/auth | jq --raw-output .challenge)" + response="$(printf "%b" "${challenge}:${pwhash}" | sha256sum | sed 's/\s.*$//')" + sessionResponse="$(curl --silent -X POST http://${URL}:${PORT}/${APIPATH}/auth --data "{\"response\":\"${response}\"}" )" + + if [ -z "${sessionResponse}" ]; then + echo "No response from FTL server. Please check connectivity and use the options to set the API URL" + echo "Usage: $0 [-u ] [-p ] [-a ] " + exit 1 + fi + # obtain validity and session ID from session response + validSession=$(echo "${sessionResponse}"| jq .session.valid) + SID=$(echo "${sessionResponse}"| jq --raw-output .session.sid) +} + +GetFTLData() { + data=$(curl -sS -X GET "http://${URL}:${PORT}/${APIPATH}$1" -H "Accept: application/json" -H "sid: ${SID}" ) + echo "${data}" +} + ############################################# GETTERS ############################################## @@ -1008,17 +1100,27 @@ VersionConverter() { OutputJSON() { GetSummaryInformation echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw},\"clients\": ${clients}}" + exit 0 } StartupRoutine(){ - # Get config variables + + # Construct FTL's API address depending on the arguments supplied + ConstructAPI + + # Get config variables . /etc/pihole/setupVars.conf if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then PrintLogo "$1" printf "%b" "START-UP ===========\n" - printf "%b" "Checking connection.\n" + printf "%b" "Checking Internet connection.\n" CheckConnectivity "$1" + + # Authenticate with the FTL server + printf "%b" "Establishing connection with FTL...\n" + Authenthication + printf "%b" "Starting PADD...\n" printf "%b" " [■·········] 10%\\r" @@ -1047,6 +1149,11 @@ StartupRoutine(){ echo "Checking connectivity." CheckConnectivity "$1" + # Authenticate with the FTL server + printf "%b" "Establishing connection with FTL...\n" + Authenthication + + echo "Starting PADD." # Get our information for the first time @@ -1076,6 +1183,11 @@ StartupRoutine(){ printf "%b" "- Checking internet connection...\n" CheckConnectivity "$1" + # Authenticate with the FTL server + printf "%b" "Establishing connection with FTL...\n" + Authenthication + + # Get our information for the first time echo "- Gathering system information..." GetSystemInformation "$1" @@ -1174,39 +1286,51 @@ DisplayHelp() { cat << EOM ::: PADD displays stats about your piHole! ::: -::: Note: If no option is passed, then stats are displayed on screen, updated every 5 seconds ::: ::: Options: -::: -j, --json output stats as JSON formatted string -::: -h, --help display this help text +::: +::: -u URL or address of your Pi-hole (default: pi.hole) +::: -p Port of your Pi-hole's API (default: 8080) +::: -a Path where your Pi-hole's API is hosted (default: api) +::: -s Your Pi-hole's password, required to access the API +::: -j output stats as JSON formatted string and exit +::: -h display this help text EOM exit 0 } -if [ $# = 0 ]; then - # Turns off the cursor - # (From Pull request #8 https://github.com/jpmck/PADD/pull/8) - setterm -cursor off - trap "{ setterm -cursor on ; echo "" ; exit 0 ; }" INT TERM EXIT +# Get supplied options - clear - - console_width=$(tput cols) - console_height=$(tput lines) - - SizeChecker - - StartupRoutine ${padd_size} - - # Run PADD - clear - NormalPADD -fi - -for var in "$@"; do - case "$var" in - "-j" | "--json" ) OutputJSON;; - "-h" | "--help" ) DisplayHelp;; - * ) exit 1;; - esac +while getopts ":u:p:a:s:jh" args; do + case "${args}" in + u) URL="${OPTARG}" ;; + p) PORT="${OPTARG}" ;; + a) APIPATH="${OPTARG}" ;; + s) password="${OPTARG}" ;; + j) OutputJSON;; + h) DisplayHelp;; + \?) echo "Invalid option: -${OPTARG}" + exit 1 ;; + :) echo "Option -$OPTARG requires an argument." + exit 1 ;; + *) DisplayHelp;; + esac done + + # Turns off the cursor +# (From Pull request #8 https://github.com/jpmck/PADD/pull/8) +setterm -cursor off +trap "{ setterm -cursor on ; echo "" ; exit 0 ; }" INT TERM EXIT + +clear + +console_width=$(tput cols) +console_height=$(tput lines) + +SizeChecker + +StartupRoutine ${padd_size} + +# Run PADD +clear +NormalPADD From 8916cb2cb4dae606ed6654f851582adf639f0afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sat, 2 Jul 2022 22:57:37 +0200 Subject: [PATCH 02/96] Improve exit routines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/padd.sh b/padd.sh index 5552f07..a74094b 100755 --- a/padd.sh +++ b/padd.sh @@ -157,9 +157,9 @@ DeleteSession() { deleteResponse=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE http://${URL}:${PORT}/${APIPATH}/auth -H "Accept: application/json" -H "sid: ${SID}") case "${deleteResponse}" in - "200") echo "A session that was not created cannot be deleted (e.g., empty API password).";; - "401") echo "Logout attempt without a valid session. Unauthorized!";; - "410") echo "Session deleted successfully";; + "200") printf "%b" "\nA session that was not created cannot be deleted (e.g., empty API password).\n";; + "401") printf "%b" "\nLogout attempt without a valid session. Unauthorized!\n";; + "410") printf "%b" "\nSession deleted successfully\n";; esac; } @@ -1280,6 +1280,8 @@ NormalPADD() { fi done + + DeleteSession } DisplayHelp() { @@ -1299,6 +1301,36 @@ EOM exit 0 } +# Called on signals INT QUIT TERM +sig_cleanup() { + # save error code (130 for SIGINT, 143 for SIGTERM, 131 for SIGQUIT) + err=$? + + # some shells will call EXIT after the INT signal + # causing EXIT trap to be executed, so we trap EXIT after INT + trap '' EXIT + + (exit $err) # execute in a subshell just to pass $? to clean_exit() + clean_exit +} + +# Called on signal EXIT, or indirectly on INT QUIT TERM +clean_exit() { + # save the return code of the script + err=$? + + # reset trap for all signals to not interrupt clean_tempfiles() on any next signal + trap '' EXIT INT QUIT TERM + + # restore terminal settings + setterm -cursor on + stty "${stty_orig}" + + # Delete session from FTL server + DeleteSession + exit $err # exit the script with saved $? +} + # Get supplied options while getopts ":u:p:a:s:jh" args; do @@ -1320,7 +1352,11 @@ done # Turns off the cursor # (From Pull request #8 https://github.com/jpmck/PADD/pull/8) setterm -cursor off -trap "{ setterm -cursor on ; echo "" ; exit 0 ; }" INT TERM EXIT + +# Traps for graceful shutdown +# https://unix.stackexchange.com/a/681201 +trap clean_exit EXIT +trap sig_cleanup INT QUIT TERM clear From 55ade42fa9639204bceafd1070c6fe1cdd4a7488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sun, 17 Jul 2022 13:54:50 +0200 Subject: [PATCH 03/96] Add TestAPIAvailability() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 103 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 40 deletions(-) diff --git a/padd.sh b/padd.sh index a74094b..4defda6 100755 --- a/padd.sh +++ b/padd.sh @@ -118,49 +118,65 @@ ConstructAPI() { fi } +TestAPIAvailability() { + + availabilityResonse=$(curl -s -o /dev/null -w "%{http_code}" http://${URL}:${PORT}/${APIPATH}/auth) + + # test if http status code was 200 (OK) + if [ "${availabilityResonse}" = 200 ]; then + printf "%b" "API available at: http://${URL}:${PORT}/${APIPATH}\n\n" + else + echo "API not available at: http://${URL}:${PORT}/${APIPATH}" + echo "Exiting." + exit 1 + fi +} + Authenthication() { - # Try to authenticate - ChallengeResponse + # Try to authenticate + ChallengeResponse - while [ "${validSession}" = false ]; do - echo "Authentication with FTL server failed." + while [ "${validSession}" = false ]; do + echo "Authentication failed." - # no password was supplied as argument - if [ -z "${password}" ]; then - echo "Please enter your Pi-hole password:" - else - echo "Wrong Pi-hole password supplied, please enter the correct password:" - fi + # no password was supplied as argument + if [ -z "${password}" ]; then + echo "No password supplied. Please enter your password:" + else + echo "Wrong password supplied, please enter the correct password:" + fi - # POSIX's `read` does not support `-s` option (suppressing the input) - # this workaround changes the terminal characteristics to not echo input and later rests this option - # credits https://stackoverflow.com/a/4316765 + # POSIX's `read` does not support `-s` option (suppressing the input) + # this workaround changes the terminal characteristics to not echo input and later rests this option + # credits https://stackoverflow.com/a/4316765 - stty_orig=$(stty -g) - stty -echo - read -r password - stty "${stty_orig}" - echo "" + stty -echo + read -r password + stty "${stty_orig}" + echo "" - # Try to authenticate again - ChallengeResponse - done + # Try to authenticate again + ChallengeResponse + done - # Loop exited, authentication was successful - echo "Authentication with FTL server successful." + # Loop exited, authentication was successful + echo "Authentication successful." } DeleteSession() { + # if a valid Session exists (no password required or successful authenthication) and + # SID is not null (successful authenthication only), delete the session + if [ "${validSession}" = true ] && [ ! "${SID}" = null ]; then + # Try to delte the session. Omitt the output, but get the http status code + deleteResponse=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE http://${URL}:${PORT}/${APIPATH}/auth -H "Accept: application/json" -H "sid: ${SID}") - # Try to delte the session. Omitt the output, but get the http status code - deleteResponse=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE http://${URL}:${PORT}/${APIPATH}/auth -H "Accept: application/json" -H "sid: ${SID}") - - case "${deleteResponse}" in - "200") printf "%b" "\nA session that was not created cannot be deleted (e.g., empty API password).\n";; - "401") printf "%b" "\nLogout attempt without a valid session. Unauthorized!\n";; - "410") printf "%b" "\nSession deleted successfully\n";; - esac; + case "${deleteResponse}" in + "200") printf "%b" "\nA session that was not created cannot be deleted (e.g., empty API password).\n";; + "401") printf "%b" "\nLogout attempt without a valid session. Unauthorized!\n";; + "410") printf "%b" "\nSession successfully deleted.\n";; + esac; + fi } @@ -1105,9 +1121,6 @@ OutputJSON() { StartupRoutine(){ - # Construct FTL's API address depending on the arguments supplied - ConstructAPI - # Get config variables . /etc/pihole/setupVars.conf @@ -1322,9 +1335,10 @@ clean_exit() { # reset trap for all signals to not interrupt clean_tempfiles() on any next signal trap '' EXIT INT QUIT TERM - # restore terminal settings - setterm -cursor on - stty "${stty_orig}" + # restore terminal settings if they have been changed (e.g. user cancled script while at password input prompt) + if [ "$(stty -g)" != "${stty_orig}" ]; then + stty "${stty_orig}" + fi # Delete session from FTL server DeleteSession @@ -1336,10 +1350,10 @@ clean_exit() { while getopts ":u:p:a:s:jh" args; do case "${args}" in u) URL="${OPTARG}" ;; - p) PORT="${OPTARG}" ;; + p) PORT="${OPTARG}" ;; a) APIPATH="${OPTARG}" ;; s) password="${OPTARG}" ;; - j) OutputJSON;; + j) OutputJSON;; h) DisplayHelp;; \?) echo "Invalid option: -${OPTARG}" exit 1 ;; @@ -1349,10 +1363,19 @@ while getopts ":u:p:a:s:jh" args; do esac done - # Turns off the cursor +# Save current terminal settings (needed for later restore after password prompt) +stty_orig=$(stty -g) + +# Turns off the cursor # (From Pull request #8 https://github.com/jpmck/PADD/pull/8) setterm -cursor off +# Construct FTL's API address depending on the arguments supplied +ConstructAPI + +# Test if the authentication endpoint is availabe +TestAPIAvailability + # Traps for graceful shutdown # https://unix.stackexchange.com/a/681201 trap clean_exit EXIT From cea974e74a486a828842103bfb1efc40580c2919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sun, 17 Jul 2022 14:25:02 +0200 Subject: [PATCH 04/96] Use API for GetSummaryInformation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 72 +++++++++++++++------------------------------------------ 1 file changed, 19 insertions(+), 53 deletions(-) diff --git a/padd.sh b/padd.sh index 4defda6..f67b285 100755 --- a/padd.sh +++ b/padd.sh @@ -54,7 +54,6 @@ pico_status_hot="${check_box_bad} Sys. Hot!" pico_status_off="${check_box_bad} Offline" pico_status_ftl_down="${check_box_info} FTL Down" pico_status_dns_down="${check_box_bad} DNS Down" -pico_status_unknown="${check_box_question} Stat. Unk." # MINI STATUS mini_status_ok="${check_box_good} System OK" @@ -63,7 +62,6 @@ mini_status_hot="${check_box_bad} System is hot!" mini_status_off="${check_box_bad} Pi-hole off!" mini_status_ftl_down="${check_box_info} FTL down!" mini_status_dns_down="${check_box_bad} DNS off!" -mini_status_unknown="${check_box_question} Status unknown" # REGULAR STATUS full_status_ok="${check_box_good} System is healthy." @@ -72,7 +70,6 @@ full_status_hot="${check_box_bad} System is hot!" full_status_off="${check_box_bad} Pi-hole is offline" full_status_ftl_down="${check_box_info} FTL is down!" full_status_dns_down="${check_box_bad} DNS is off!" -full_status_unknown="${check_box_question} Status unknown!" # MEGA STATUS mega_status_ok="${check_box_good} Your system is healthy." @@ -81,7 +78,6 @@ mega_status_hot="${check_box_bad} Your system is hot!" mega_status_off="${check_box_bad} Pi-hole is offline." mega_status_ftl_down="${check_box_info} FTLDNS service is not running." mega_status_dns_down="${check_box_bad} Pi-hole's DNS server is off!" -mega_status_unknown="${check_box_question} Unable to determine Pi-hole status." # TINY STATUS tiny_status_ok="${check_box_good} System is healthy." @@ -90,7 +86,6 @@ tiny_status_hot="${check_box_bad} System is hot!" tiny_status_off="${check_box_bad} Pi-hole is offline" tiny_status_ftl_down="${check_box_info} FTL is down!" tiny_status_dns_down="${check_box_bad} DNS is off!" -tiny_status_unknown="${check_box_question} Status unknown!" # Text only "logos" padd_text="${green_text}${bold_text}PADD${reset_text}" @@ -214,52 +209,37 @@ GetFTLData() { ############################################# GETTERS ############################################## -GetFTLData() { - ftl_port=$(cat /run/pihole-FTL.port 2> /dev/null) - if [ -n "$ftl_port" ]; then - # Send command to FTL and ask to quit when finished - echo ">$1 >quit" | nc 127.0.0.1 "${ftl_port}" - else - echo "0" - fi -} - GetSummaryInformation() { - summary=$(GetFTLData "stats") - cache_info=$(GetFTLData "cacheinfo") + summary=$(GetFTLData "/stats/summary") + cache_info=$(GetFTLData "/dns/cache") - clients=$(echo "${summary}" | grep "unique_clients" | grep -Eo "[0-9]+$") + clients=$(echo "${summary}" | jq .ftl.clients.active ) - blocking_status=$(echo "${summary}" | grep "status" | grep -Eo "enabled|disabled|unknown" ) + blocking_status=$(echo "${summary}" | jq .system.dns.blocking ) - domains_being_blocked_raw=$(echo "${summary}" | grep "domains_being_blocked" | grep -Eo "[0-9]+$") + domains_being_blocked_raw=$(echo "${summary}" | jq .ftl.database.gravity ) domains_being_blocked=$(printf "%.f" "${domains_being_blocked_raw}") - dns_queries_today_raw=$(echo "$summary" | grep "dns_queries_today" | grep -Eo "[0-9]+$") + dns_queries_today_raw=$(echo "$summary" | jq .queries.total ) dns_queries_today=$(printf "%.f" "${dns_queries_today_raw}") - ads_blocked_today_raw=$(echo "$summary" | grep "ads_blocked_today" | grep -Eo "[0-9]+$") + ads_blocked_today_raw=$(echo "$summary" | jq .queries.blocked ) ads_blocked_today=$(printf "%.f" "${ads_blocked_today_raw}") - ads_percentage_today_raw=$(echo "$summary" | grep "ads_percentage_today" | grep -Eo "[0-9.]+$") + ads_percentage_today_raw=$(echo "$summary" | jq .queries.percent_blocked) ads_percentage_today=$(printf "%.1f" "${ads_percentage_today_raw}") - cache_size=$(echo "$cache_info" | grep "cache-size" | grep -Eo "[0-9.]+$") - cache_deletes=$(echo "$cache_info" | grep "cache-live-freed" | grep -Eo "[0-9.]+$") - cache_inserts=$(echo "$cache_info"| grep "cache-inserted" | grep -Eo "[0-9.]+$") + cache_size=$(echo "$cache_info" | jq .size) + cache_evictions=$(echo "$cache_info" | jq .evicted) + cache_inserts=$(echo "$cache_info"| jq .inserted) - latest_blocked=$(GetFTLData recentBlocked) + latest_blocked=$(GetFTLData "/stats/recent_blocked" | jq --raw-output .blocked[0]) - top_blocked=$(GetFTLData "top-ads (1)" | awk '{print $3}') + top_blocked=$(GetFTLData "/stats/top_blocked" | jq --raw-output .top_domains[0].domain) - top_domain=$(GetFTLData "top-domains (1)" | awk '{print $3}') + top_domain=$(GetFTLData "/stats/top_domains" | jq --raw-output .top_domains[0].domain) - top_client_raw=$(GetFTLData "top-clients (1)" | awk '{print $4}') - if [ -z "${top_client_raw}" ]; then - top_client=$(GetFTLData "top-clients (1)" | awk '{print $3}') - else - top_client="${top_client_raw}" - fi + top_client=$(GetFTLData "/stats/top_clients " | jq --raw-output .top_clients[0].name) if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then ads_blocked_bar=$(BarGenerator "$ads_percentage_today" 10 "color") @@ -533,7 +513,7 @@ GetPiholeInformation() { fi # Get Pi-hole (blocking) status - ftl_dns_port=$(GetFTLData "dns-port") + ftl_dns_port=$(GetFTLData "/dns/port" | jq .dns-port) # ${ftl_dns_port} == 0 DNS server part of dnsmasq disabled, ${ftl_status} == "Not running" no ftlPID found if [ "${ftl_dns_port}" = 0 ] || [ "${ftl_status}" = "Not running" ]; then @@ -546,12 +526,12 @@ GetPiholeInformation() { full_status=${full_status_dns_down} mega_status=${mega_status_dns_down} else - if [ "${blocking_status}" = "enabled" ]; then + if [ "${blocking_status}" = "true" ]; then pihole_status="Active" pihole_heatmap=${green_text} pihole_check_box=${check_box_good} fi - if [ "${blocking_status}" = "disabled" ]; then + if [ "${blocking_status}" = "false" ]; then pihole_status="Blocking disabled" pihole_heatmap=${red_text} pihole_check_box=${check_box_bad} @@ -561,16 +541,6 @@ GetPiholeInformation() { full_status=${full_status_off} mega_status=${mega_status_off} fi - if [ "${blocking_status}" = "unknown" ]; then - pihole_status="Unknown" - pihole_heatmap=${yellow_text} - pihole_check_box=${check_box_question} - pico_status=${pico_status_unknown} - mini_status=${mini_status_unknown} - tiny_status=${tiny_status_unknown} - full_status=${full_status_unknown} - mega_status=${mega_status_unknown} - fi fi } @@ -891,7 +861,7 @@ PrintPiholeStats() { CleanPrintf " %-10s%-39s\e[0K\\n" "Top Clnt:" "${top_client}" CleanEcho "FTL ===========================================================================" CleanPrintf " %-10s%-9s %-10s%-9s %-10s%-9s\e[0K\\n" "PID:" "${ftlPID}" "CPU Use:" "${ftl_cpu}%" "Mem. Use:" "${ftl_mem_percentage}%" - CleanPrintf " %-10s%-69s\e[0K\\n" "DNSCache:" "${cache_inserts} insertions, ${cache_deletes} deletions, ${cache_size} total entries" + CleanPrintf " %-10s%-69s\e[0K\\n" "DNSCache:" "${cache_inserts} insertions, ${cache_evictions} evictions, ${cache_size} total entries" fi } @@ -1121,9 +1091,6 @@ OutputJSON() { StartupRoutine(){ - # Get config variables - . /etc/pihole/setupVars.conf - if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then PrintLogo "$1" printf "%b" "START-UP ===========\n" @@ -1263,7 +1230,6 @@ NormalPADD() { # Get uptime, CPU load, temp, etc. every 5 seconds if [ $((now - LastCheckSystemInformation)) -ge 5 ]; then - . /etc/pihole/setupVars.conf GetSystemInformation ${padd_size} LastCheckSystemInformation="${now}" fi From 0df566a2e3d11091c7cf5135f5f0c21b5f2f2413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sun, 17 Jul 2022 20:23:33 +0200 Subject: [PATCH 05/96] Use API for GetSystemInformation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 125 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 62 insertions(+), 63 deletions(-) diff --git a/padd.sh b/padd.sh index f67b285..7ec86a0 100755 --- a/padd.sh +++ b/padd.sh @@ -23,9 +23,6 @@ LastCheckSummaryInformation=$(date +%s) LastCheckPiholeInformation=$(date +%s) LastCheckSystemInformation=$(date +%s) -# CORES -core_count=$(nproc --all 2> /dev/null) - # COLORS CSI="$(printf '\033')[" red_text="${CSI}91m" # Red @@ -233,7 +230,7 @@ GetSummaryInformation() { cache_evictions=$(echo "$cache_info" | jq .evicted) cache_inserts=$(echo "$cache_info"| jq .inserted) - latest_blocked=$(GetFTLData "/stats/recent_blocked" | jq --raw-output .blocked[0]) + latest_blocked=$(GetFTLData "/stats/recent_blocked&show=1" | jq --raw-output .blocked[0]) top_blocked=$(GetFTLData "/stats/top_blocked" | jq --raw-output .top_domains[0].domain) @@ -279,60 +276,60 @@ GetSummaryInformation() { } GetSystemInformation() { - # System uptime - if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then - system_uptime=$(uptime | awk -F'( |,|:)+' '{if ($7=="min") m=$6; else {if ($7~/^day/){if ($9=="min") {d=$6;m=$8} else {d=$6;h=$8;m=$9}} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours"}') - else - system_uptime=$(uptime | awk -F'( |,|:)+' '{if ($7=="min") m=$6; else {if ($7~/^day/){if ($9=="min") {d=$6;m=$8} else {d=$6;h=$8;m=$9}} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes"}') - fi + # System uptime + system_uptime_raw=$(echo "${summary}" | jq .system.uptime ) + if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then + system_uptime="$(printf '%d days, %d hours' $((system_uptime_raw/86400)) $((system_uptime_raw%86400/3600)))" + else + system_uptime="$(printf '%d days, %d hours, %d minutes' $((system_uptime_raw/86400)) $((system_uptime_raw%86400/3600)) $((system_uptime_raw%3600/60)))" + fi - # CPU temperature - if [ -f /sys/class/thermal/thermal_zone0/temp ]; then - cpu=$(cat /sys/class/thermal/thermal_zone0/temp) - elif [ -f /sys/class/hwmon/hwmon0/temp1_input ]; then - cpu=$(cat /sys/class/hwmon/hwmon0/temp1_input) - else - cpu=0 - fi + # CPU temperature is returned in °C + cpu_temp=$(echo "${summary}" | jq .system.sensors[0].value ) - # Convert CPU temperature to correct unit - if [ "${TEMPERATUREUNIT}" = "F" ]; then - temperature="$(printf %.1f "$(echo "${cpu}" | awk '{print $1 * 9 / 5000 + 32}')")°F" - elif [ "${TEMPERATUREUNIT}" = "K" ]; then - temperature="$(printf %.1f "$(echo "${cpu}" | awk '{print $1 / 1000 + 273.15}')")°K" - # Addresses Issue 1: https://github.com/jpmck/PAD/issues/1 - else - temperature="$(printf %.1f "$(echo "${cpu}" | awk '{print $1 / 1000}')")°C" - fi + # Convert CPU temperature to correct unit + if [ "${TEMPERATUREUNIT}" = "F" ]; then + temperature="$(printf %.1f "$(echo "${cpu_temp}" | awk '{print $1 * 9 / 5 + 32}')")°F" + elif [ "${TEMPERATUREUNIT}" = "K" ]; then + temperature="$(printf %.1f "$(echo "${cpu_temp}" | awk '{print $1 + 273.15}')")°K" + else + temperature="$(printf %.1f "${cpu_temp}" )°C" + fi - # CPU load, heatmap - cpu_load_1=$(awk '{print $1}' < /proc/loadavg) - cpu_load_5=$(awk '{print $2}' < /proc/loadavg) - cpu_load_15=$(awk '{print $3}' < /proc/loadavg) - cpu_load_1_heatmap=$(HeatmapGenerator "${cpu_load_1}" "${core_count}") - cpu_load_5_heatmap=$(HeatmapGenerator "${cpu_load_5}" "${core_count}") - cpu_load_15_heatmap=$(HeatmapGenerator "${cpu_load_15}" "${core_count}") - cpu_percent=$(printf %.1f "$(echo "${cpu_load_1} ${core_count}" | awk '{print ($1 / $2) * 100}')") + # CPU, load, heatmap + core_count=$(echo "${summary}" | jq .system.cpu.nprocs) + cpu_load_1=$(printf %.2f "$(echo "${summary}" | jq .system.cpu.load.raw[0])") + cpu_load_5=$(printf %.2f "$(echo "${summary}" | jq .system.cpu.load.raw[1])") + cpu_load_15=$(printf %.2f "$(echo "${summary}" | jq .system.cpu.load.raw[2])") + cpu_load_1_heatmap=$(HeatmapGenerator "${cpu_load_1}" "${core_count}") + cpu_load_5_heatmap=$(HeatmapGenerator "${cpu_load_5}" "${core_count}") + cpu_load_15_heatmap=$(HeatmapGenerator "${cpu_load_15}" "${core_count}") + cpu_percent=$(printf %.1f "$(echo "${summary}" | jq .system.cpu.load.percent[0])") - # CPU temperature heatmap - # If we're getting close to 85°C... (https://www.raspberrypi.org/blog/introducing-turbo-mode-up-to-50-more-performance-for-free/) - if [ ${cpu} -gt 80000 ]; then - temp_heatmap=${blinking_text}${red_text} - pico_status="${pico_status_hot}" - mini_status="${mini_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" - tiny_status="${tiny_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" - full_status="${full_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" - mega_status="${mega_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" - elif [ ${cpu} -gt 70000 ]; then - temp_heatmap=${magenta_text} - elif [ ${cpu} -gt 60000 ]; then - temp_heatmap=${blue_text} - else - temp_heatmap=${cyan_text} - fi + # CPU temperature heatmap + # If we're getting close to 85°C... (https://www.raspberrypi.org/blog/introducing-turbo-mode-up-to-50-more-performance-for-free/) + + # Remove decimal accuracy + cpu_temp=$(echo "${cpu_temp}" | cut -d '.' -f1) + if [ "${cpu_temp}" -gt 80 ]; then + temp_heatmap=${blinking_text}${red_text} + pico_status="${pico_status_hot}" + mini_status="${mini_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" + tiny_status="${tiny_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" + full_status="${full_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" + mega_status="${mega_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" + elif [ "${cpu_temp}" -gt 70 ]; then + temp_heatmap=${magenta_text} + elif [ "${cpu_temp}" -gt 60 ]; then + temp_heatmap=${blue_text} + else + temp_heatmap=${cyan_text} + fi # Memory use, heatmap and bar - memory_percent=$(awk '/MemTotal:/{total=$2} /MemFree:/{free=$2} /Buffers:/{buffers=$2} /^Cached:/{cached=$2} END {printf "%.1f", (total-free-buffers-cached)*100/total}' '/proc/meminfo') + memory_total=$(echo "${summary}" | jq .system.memory.ram.total) + memory_available=$(echo "${summary}" | jq .system.memory.ram.available) + memory_percent=$(printf %.1f $(((memory_total-memory_available)*100/memory_total)) ) memory_heatmap=$(HeatmapGenerator "${memory_percent}") # Bar generations @@ -513,7 +510,7 @@ GetPiholeInformation() { fi # Get Pi-hole (blocking) status - ftl_dns_port=$(GetFTLData "/dns/port" | jq .dns-port) + ftl_dns_port=$(GetFTLData "/dns/port" | jq .dns_port) # ${ftl_dns_port} == 0 DNS server part of dnsmasq disabled, ${ftl_status} == "Not running" no ftlPID found if [ "${ftl_dns_port}" = 0 ] || [ "${ftl_status}" = "Not running" ]; then @@ -1111,9 +1108,9 @@ StartupRoutine(){ # Get our information for the first time printf "%b" " [■■■■······] 40%\\r" - GetSystemInformation "$1" - printf "%b" " [■■■■■·····] 50%\\r" GetSummaryInformation "$1" + printf "%b" " [■■■■■·····] 50%\\r" + GetSystemInformation "$1" printf "%b" " [■■■■■■····] 60%\\r" GetPiholeInformation "$1" printf "%b" " [■■■■■■■···] 70%\\r" @@ -1137,11 +1134,12 @@ StartupRoutine(){ echo "Starting PADD." # Get our information for the first time + echo "- Gathering Summary info." + GetSummaryInformation "mini" echo "- Gathering system info." GetSystemInformation "mini" echo "- Gathering Pi-hole info." GetPiholeInformation "mini" - GetSummaryInformation "mini" echo "- Gathering network info." GetNetworkInformation "mini" echo "- Gathering version info." @@ -1169,10 +1167,11 @@ StartupRoutine(){ # Get our information for the first time + echo "- Gathering Summary information..." + GetSummaryInformation "$1" echo "- Gathering system information..." GetSystemInformation "$1" echo "- Gathering Pi-hole information..." - GetSummaryInformation "$1" GetPiholeInformation "$1" echo "- Gathering network information..." GetNetworkInformation "$1" @@ -1228,18 +1227,18 @@ NormalPADD() { # Start getting our information for next round now=$(date +%s) - # Get uptime, CPU load, temp, etc. every 5 seconds - if [ $((now - LastCheckSystemInformation)) -ge 5 ]; then - GetSystemInformation ${padd_size} - LastCheckSystemInformation="${now}" - fi - # Get cache info, last ad domain, blocking percentage, etc. every 5 seconds if [ $((now - LastCheckSummaryInformation)) -ge 5 ]; then GetSummaryInformation ${padd_size} LastCheckSummaryInformation="${now}" fi + # Get uptime, CPU load, temp, etc. every 5 seconds + if [ $((now - LastCheckSystemInformation)) -ge 5 ]; then + GetSystemInformation ${padd_size} + LastCheckSystemInformation="${now}" + fi + # Get FTL status every 5 seconds if [ $((now - LastCheckPiholeInformation)) -ge 5 ]; then GetPiholeInformation ${padd_size} From 67184b79d40f7eb051ce3d248854b2c9593e25ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 18 Jul 2022 11:26:51 +0200 Subject: [PATCH 06/96] Use API for GetNetworkInformation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 62 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/padd.sh b/padd.sh index 7ec86a0..faa8f48 100755 --- a/padd.sh +++ b/padd.sh @@ -166,7 +166,7 @@ DeleteSession() { case "${deleteResponse}" in "200") printf "%b" "\nA session that was not created cannot be deleted (e.g., empty API password).\n";; "401") printf "%b" "\nLogout attempt without a valid session. Unauthorized!\n";; - "410") printf "%b" "\nSession successfully deleted.\n";; + "410") printf "%b" "\n\nSession successfully deleted.\n";; esac; fi @@ -230,7 +230,7 @@ GetSummaryInformation() { cache_evictions=$(echo "$cache_info" | jq .evicted) cache_inserts=$(echo "$cache_info"| jq .inserted) - latest_blocked=$(GetFTLData "/stats/recent_blocked&show=1" | jq --raw-output .blocked[0]) + latest_blocked=$(GetFTLData "/stats/recent_blocked?show=1" | jq --raw-output .blocked[0]) top_blocked=$(GetFTLData "/stats/top_blocked" | jq --raw-output .top_domains[0].domain) @@ -344,45 +344,41 @@ GetSystemInformation() { memory_bar=$(BarGenerator "${memory_percent}" 10) fi - # Device model - if [ -f /sys/firmware/devicetree/base/model ]; then - # Get model, remove possible null byte - sys_model=$(tr -d '\0' < /sys/firmware/devicetree/base/model) - else - sys_model="" - fi + # Device model + sys_model=$(echo "${summary}" | jq --raw-output .system.model) } GetNetworkInformation() { - # Get pi IPv4 address - pi_ip4_addrs="$(ip addr | grep 'inet ' | grep -v '127.0.0.1/8' | awk '{print $2}' | cut -f1 -d'/' |wc -l)" - if [ "${pi_ip4_addrs}" -eq 0 ]; then - # No IPv4 address available - pi_ip4_addr="N/A" - elif [ "${pi_ip4_addrs}" -eq 1 ]; then - # One IPv4 address available - pi_ip4_addr="$(ip addr | grep 'inet ' | grep -v '127.0.0.1/8' | awk '{print $2}' | cut -f1 -d'/' | head -n 1)" - else - # More than one IPv4 address available - pi_ip4_addr="$(ip addr | grep 'inet ' | grep -v '127.0.0.1/8' | awk '{print $2}' | cut -f1 -d'/' | head -n 1)+" - fi + interfaces_raw=$(GetFTLData "/ftl/interfaces") + # Get pi IPv4 address of the default interface + pi_ip4_addrs="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].ipv4 | sed "s/127.0.0.1,//g" | tr "," " " | wc -w)" + if [ "${pi_ip4_addrs}" -eq 0 ]; then + # No IPv4 address available + pi_ip4_addr="N/A" + elif [ "${pi_ip4_addrs}" -eq 1 ]; then + # One IPv4 address available + pi_ip4_addr="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].ipv4 | sed "s/127.0.0.1,//g" | awk -F ',' '{printf $1}')" + else + # More than one IPv4 address available + pi_ip4_addr="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].ipv4 | sed "s/127.0.0.1,//g"| awk -F ',' '{printf $1}')+" + fi - # Get pi IPv6 address - pi_ip6_addrs="$(ip addr | grep 'inet6 ' | grep -v '::1/128' | awk '{print $2}' | cut -f1 -d'/' | wc -l)" + # Get pi IPv6 address of the default interface + pi_ip6_addrs="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].ipv6 | sed "s/::1,//g" | tr "," " " | wc -w)" if [ "${pi_ip6_addrs}" -eq 0 ]; then # No IPv6 address available pi_ip6_addr="N/A" elif [ "${pi_ip6_addrs}" -eq 1 ]; then # One IPv6 address available - pi_ip6_addr="$(ip addr | grep 'inet6 ' | grep -v '::1/128' | awk '{print $2}' | cut -f1 -d'/' | head -n 1)" + pi_ip6_addr="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].ipv6 | sed "s/::1,//g" | awk -F ',' '{printf $1}')" else # More than one IPv6 address available - pi_ip6_addr="$(ip addr | grep 'inet6 ' | grep -v '::1/128' | awk '{print $2}' | cut -f1 -d'/' | head -n 1)+" + pi_ip6_addr="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].ipv6 | sed "s/::1,//g" | awk -F ',' '{printf $1}')+" fi # Get hostname and gateway pi_hostname=$(hostname) - pi_gateway=$(ip r | grep 'default' | awk '{print $3}') + pi_gateway=$(echo "${interfaces_raw}" | jq --raw-output .gateway.address) full_hostname=${pi_hostname} # does the Pi-hole have a domain set? @@ -481,11 +477,15 @@ GetNetworkInformation() { conditional_forwarding_heatmap=${red_text} fi - #Default interface data - def_iface_data=$(GetFTLData "interfaces" | head -n1) - iface_name="$(echo "$def_iface_data" | awk '{print $1}')" - tx_bytes="$(echo "$def_iface_data" | awk '{print $4}')" - rx_bytes="$(echo "$def_iface_data" | awk '{print $5}')" + #Default interface data + iface_name="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].name)" + tx_bytes="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].tx.num)" + tx_bytes_unit="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].tx.unit)" + tx_bytes=$(printf "%.1f %b" "${tx_bytes}" "${tx_bytes_unit}") + + rx_bytes="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].rx.num)" + rx_bytes_unit="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].rx.unit)" + rx_bytes=$(printf "%.1f %b" "${rx_bytes}" "${rx_bytes_unit}") } GetPiholeInformation() { From f92afc742912061b32fe24277cece21b0198e858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 18 Jul 2022 14:07:12 +0200 Subject: [PATCH 07/96] Use API for GetVersionInformation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 138 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 72 insertions(+), 66 deletions(-) diff --git a/padd.sh b/padd.sh index faa8f48..4ab329c 100755 --- a/padd.sh +++ b/padd.sh @@ -543,77 +543,83 @@ GetPiholeInformation() { } GetVersionInformation() { - # Check if version status has been saved - core_version=$(pihole -v -p | awk '{print $4}' | tr -d '[:alpha:]') - core_version_latest=$(pihole -v -p | awk '{print $(NF)}' | tr -d ')') - # if core_version is something else then x.xx or x.xx.xxx set it to N/A - if ! echo "${core_version}" | grep -qE '^[0-9]+([.][0-9]+){1,2}$' || [ "${core_version_latest}" = "ERROR" ]; then - core_version="N/A" - core_version_heatmap=${yellow_text} - else - # remove the leading "v" from core_version_latest - core_version_latest=$(echo "${core_version_latest}" | tr -d '\r\n[:alpha:]') - # is core up-to-date? - if [ "${core_version}" != "${core_version_latest}" ]; then - out_of_date_flag="true" - core_version_heatmap=${red_text} + versions_raw=$(GetFTLData "/version") + + # Check if core version + core_branch="$(echo "${versions_raw}" | jq --raw-output .core.branch)" + core_version=$(echo "${versions_raw}" | jq --raw-output .core.tag | tr -d '[:alpha:]' | awk -F '-' '{printf $1}') + core_version_latest=$(pihole -v -p | awk '{print $(NF)}' | tr -d ')') + + # if core_version is something else then x.xx or x.xx.xxx or branch not master set it to N/A + if ! echo "${core_version}" | grep -qE '^[0-9]+([.][0-9]+){1,2}$' || [ ! "${core_branch}" = "master" ]; then + core_version="N/A" + core_version_heatmap=${yellow_text} else - core_version_heatmap=${green_text} + # remove the leading "v" from core_version_latest + core_version_latest=$(echo "${core_version_latest}" | tr -d '\r\n[:alpha:]') + # is core up-to-date? + if [ "${core_version}" != "${core_version_latest}" ]; then + out_of_date_flag="true" + core_version_heatmap=${red_text} + else + core_version_heatmap=${green_text} + fi + # add leading "v" to version number + core_version="v${core_version}" fi + + # Gather web version information... + if [ "$INSTALL_WEB_INTERFACE" = true ]; then + web_branch="$(echo "${versions_raw}" | jq --raw-output .web.branch)" + web_version=$(echo "${versions_raw}" | jq --raw-output .web.tag | tr -d '[:alpha:]' | awk -F '-' '{printf $1}') + web_version_latest=$(pihole -v -a | awk '{print $(NF)}' | tr -d ')') + + # if web_version is something else then x.xx or x.xx.xxx or branch not master set it to N/A + if ! echo "${web_version}" | grep -qE '^[0-9]+([.][0-9]+){1,2}$' || [ ! "${web_branch}" = "master" ]; then + web_version="N/A" + web_version_heatmap=${yellow_text} + else + # remove the leading "v" from web_version_latest + web_version_latest=$(echo "${web_version_latest}" | tr -d '\r\n[:alpha:]') + # is web up-to-date? + if [ "${web_version}" != "${web_version_latest}" ]; then + out_of_date_flag="true" + web_version_heatmap=${red_text} + else + web_version_heatmap=${green_text} + fi + # add leading "v" to version number + web_version="v${web_version}" + fi + else + # Web interface not installed + web_version="N/A" + web_version_heatmap=${yellow_text} + fi + + # Gather FTL version information... + ftl_branch="$(echo "${versions_raw}" | jq --raw-output .ftl.branch)" + ftl_version=$(echo "${versions_raw}" | jq --raw-output .ftl.tag | tr -d '[:alpha:]' | awk -F '-' '{printf $1}') + ftl_version_latest=$(pihole -v -f | awk '{print $(NF)}' | tr -d ')') + + # if ftl_version is something else then x.xx or x.xx.xxx or branch not master set it to N/A + if ! echo "${ftl_version}" | grep -qE '^[0-9]+([.][0-9]+){1,2}$' || [ ! "${ftl_branch}" = "master" ]; then + ftl_version="N/A" + ftl_version_heatmap=${yellow_text} + else + # remove the leading "v" from ftl_version_latest + ftl_version_latest=$(echo "${ftl_version_latest}" | tr -d '\r\n[:alpha:]') + # is ftl up-to-date? + if [ "${ftl_version}" != "${ftl_version_latest}" ]; then + out_of_date_flag="true" + ftl_version_heatmap=${red_text} + else + ftl_version_heatmap=${green_text} + fi # add leading "v" to version number - core_version="v${core_version}" - fi - - # Gather web version information... - if [ "$INSTALL_WEB_INTERFACE" = true ]; then - web_version=$(pihole -v -a | awk '{print $4}' | tr -d '[:alpha:]') - web_version_latest=$(pihole -v -a | awk '{print $(NF)}' | tr -d ')') - - # if web_version is something else then x.xx or x.xx.xxx set it to N/A - if ! echo "${web_version}" | grep -qE '^[0-9]+([.][0-9]+){1,2}$' || [ "${web_version_latest}" = "ERROR" ]; then - web_version="N/A" - web_version_heatmap=${yellow_text} - else - # remove the leading "v" from web_version_latest - web_version_latest=$(echo "${web_version_latest}" | tr -d '\r\n[:alpha:]') - # is web up-to-date? - if [ "${web_version}" != "${web_version_latest}" ]; then - out_of_date_flag="true" - web_version_heatmap=${red_text} - else - web_version_heatmap=${green_text} - fi - # add leading "v" to version number - web_version="v${web_version}" + ftl_version="v${ftl_version}" fi - else - # Web interface not installed - web_version="N/A" - web_version_heatmap=${yellow_text} - fi - - # Gather FTL version information... - ftl_version=$(pihole -v -f | awk '{print $4}' | tr -d '[:alpha:]') - ftl_version_latest=$(pihole -v -f | awk '{print $(NF)}' | tr -d ')') - - # if ftl_version is something else then x.xx or x.xx.xxx set it to N/A - if ! echo "${ftl_version}" | grep -qE '^[0-9]+([.][0-9]+){1,2}$' || [ "${ftl_version_latest}" = "ERROR" ]; then - ftl_version="N/A" - ftl_version_heatmap=${yellow_text} - else - # remove the leading "v" from ftl_version_latest - ftl_version_latest=$(echo "${ftl_version_latest}" | tr -d '\r\n[:alpha:]') - # is ftl up-to-date? - if [ "${ftl_version}" != "${ftl_version_latest}" ]; then - out_of_date_flag="true" - ftl_version_heatmap=${red_text} - else - ftl_version_heatmap=${green_text} - fi - # add leading "v" to version number - ftl_version="v${ftl_version}" - fi # PADD version information... padd_version_latest="$(curl --silent https://api.github.com/repos/pi-hole/PADD/releases/latest | grep '"tag_name":' | awk -F \" '{print $4}')" From 7531a1a45928b6a7841bf05d39bb2929f53dc7ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 18 Jul 2022 14:09:54 +0200 Subject: [PATCH 08/96] Remove CheckConnectivity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 69 --------------------------------------------------------- 1 file changed, 69 deletions(-) diff --git a/padd.sh b/padd.sh index 4ab329c..97ea5ff 100755 --- a/padd.sh +++ b/padd.sh @@ -639,7 +639,6 @@ GetVersionInformation() { fi fi - # was any portion of Pi-hole out-of-date? # yes, pi-hole is out of date if [ "${out_of_date_flag}" = "true" ]; then @@ -1016,68 +1015,6 @@ SizeChecker(){ fi } -CheckConnectivity() { - connectivity="false" - connection_attempts=1 - wait_timer=1 - - while [ $connection_attempts -lt 9 ]; do - - if nc -zw1 google.com 443 2>/dev/null; then - if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then - echo "Attempt #${connection_attempts} passed..." - elif [ "$1" = "mini" ]; then - echo "Attempt ${connection_attempts} passed." - else - echo " - Attempt ${connection_attempts} passed... " - fi - - connectivity="true" - connection_attempts=11 - else - connection_attempts=$((connection_attempts+1)) - - inner_wait_timer=$((wait_timer*1)) - - # echo "$wait_timer = $inner_wait_timer" - while [ $inner_wait_timer -gt 0 ]; do - if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then - printf "%b" "Attempt #${connection_attempts} failed...\\r" - elif [ "$1" = "mini" ] || [ "$1" = "tiny" ]; then - printf "%b" "- Attempt ${connection_attempts} failed, wait ${inner_wait_timer} \\r" - else - printf "%b" " - Attempt ${connection_attempts} failed... waiting ${inner_wait_timer} seconds... \\r" - fi - sleep 1 - inner_wait_timer=$((inner_wait_timer-1)) - done - - # echo -ne "Attempt $connection_attempts failed... waiting $wait_timer seconds...\\r" - # sleep $wait_timer - wait_timer=$((wait_timer*2)) - fi - - done - - if [ "$connectivity" = "false" ]; then - if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then - echo "Check failed..." - elif [ "$1" = "mini" ] || [ "$1" = "tiny" ]; then - echo "- Connectivity check failed." - else - echo " - Connectivity check failed..." - fi - else - if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then - echo "Check passed..." - elif [ "$1" = "mini" ] || [ "$1" = "tiny" ]; then - echo "- Connectivity check passed." - else - echo " - Connectivity check passed..." - fi - fi -} - # converts a given version string e.g. v3.7.1 to 3007001000 to allow for easier comparison of multi digit version numbers # credits https://apple.stackexchange.com/a/123408 VersionConverter() { @@ -1097,8 +1034,6 @@ StartupRoutine(){ if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then PrintLogo "$1" printf "%b" "START-UP ===========\n" - printf "%b" "Checking Internet connection.\n" - CheckConnectivity "$1" # Authenticate with the FTL server printf "%b" "Establishing connection with FTL...\n" @@ -1129,8 +1064,6 @@ StartupRoutine(){ elif [ "$1" = "mini" ]; then PrintLogo "$1" echo "START UP =====================" - echo "Checking connectivity." - CheckConnectivity "$1" # Authenticate with the FTL server printf "%b" "Establishing connection with FTL...\n" @@ -1164,8 +1097,6 @@ StartupRoutine(){ echo "START UP ===================================================" fi - printf "%b" "- Checking internet connection...\n" - CheckConnectivity "$1" # Authenticate with the FTL server printf "%b" "Establishing connection with FTL...\n" From cc9a9f83d183665a7856f5a6ea84917f6884a728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 18 Jul 2022 19:23:32 +0200 Subject: [PATCH 09/96] Set DHCP_ROUTER via API, turn cursor back on when exiting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/padd.sh b/padd.sh index 97ea5ff..b114adc 100755 --- a/padd.sh +++ b/padd.sh @@ -236,7 +236,7 @@ GetSummaryInformation() { top_domain=$(GetFTLData "/stats/top_domains" | jq --raw-output .top_domains[0].domain) - top_client=$(GetFTLData "/stats/top_clients " | jq --raw-output .top_clients[0].name) + top_client=$(GetFTLData "/stats/top_clients" | jq --raw-output .top_clients[0].name) if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then ads_blocked_bar=$(BarGenerator "$ads_percentage_today" 10 "color") @@ -445,9 +445,8 @@ GetNetworkInformation() { dhcp_check_box=${check_box_bad} # if the DHCP Router variable isn't set - # Issue 3: https://github.com/jpmck/PADD/issues/3 if [ -z ${DHCP_ROUTER+x} ]; then - DHCP_ROUTER=$(GetFTLData "gateway" | awk '{ printf $1 }') + DHCP_ROUTER=$(printf %b "${interfaces_raw}" | jq --raw-output .gateway.address) fi dhcp_info=" Router: ${DHCP_ROUTER}" @@ -1242,6 +1241,9 @@ clean_exit() { stty "${stty_orig}" fi + # Turn cursor on + setterm -cursor on + # Delete session from FTL server DeleteSession exit $err # exit the script with saved $? From 0e008799b00535d733b7c08f7421644790a040ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 18 Jul 2022 22:21:03 +0200 Subject: [PATCH 10/96] Make OutputJSON compatible with FTLv6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/padd.sh b/padd.sh index b114adc..cd14dc6 100755 --- a/padd.sh +++ b/padd.sh @@ -116,7 +116,7 @@ TestAPIAvailability() { # test if http status code was 200 (OK) if [ "${availabilityResonse}" = 200 ]; then - printf "%b" "API available at: http://${URL}:${PORT}/${APIPATH}\n\n" + printf "%b" "API available at: http://${URL}:${PORT}/${APIPATH}\n" else echo "API not available at: http://${URL}:${PORT}/${APIPATH}" echo "Exiting." @@ -307,8 +307,6 @@ GetSystemInformation() { cpu_percent=$(printf %.1f "$(echo "${summary}" | jq .system.cpu.load.percent[0])") # CPU temperature heatmap - # If we're getting close to 85°C... (https://www.raspberrypi.org/blog/introducing-turbo-mode-up-to-50-more-performance-for-free/) - # Remove decimal accuracy cpu_temp=$(echo "${cpu_temp}" | cut -d '.' -f1) if [ "${cpu_temp}" -gt 80 ]; then @@ -1023,9 +1021,24 @@ VersionConverter() { ########################################## MAIN FUNCTIONS ########################################## OutputJSON() { - GetSummaryInformation - echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw},\"clients\": ${clients}}" - exit 0 + # Traps for graceful shutdown + # https://unix.stackexchange.com/a/681201 + trap clean_exit EXIT + trap sig_cleanup INT QUIT TERM + + # Save current terminal settings (needed for later restore after password prompt) + stty_orig=$(stty -g) + # Construct FTL's API address depending on the arguments supplied + ConstructAPI + # Test if the authentication endpoint is availabe + TestAPIAvailability + # Authenticate with the FTL server + printf "%b" "Establishing connection with FTL...\n" + Authenthication + + GetSummaryInformation + echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today},\"clients\": ${clients}}" + exit 0 } StartupRoutine(){ @@ -1209,8 +1222,8 @@ DisplayHelp() { ::: -p Port of your Pi-hole's API (default: 8080) ::: -a Path where your Pi-hole's API is hosted (default: api) ::: -s Your Pi-hole's password, required to access the API -::: -j output stats as JSON formatted string and exit -::: -h display this help text +::: -j output stats as JSON formatted string and exit +::: -h display this help text EOM exit 0 } From bb6f8b356229498a44b6a9e519696974c731114c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 18 Jul 2022 22:27:18 +0200 Subject: [PATCH 11/96] Remove commas between component's version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/padd.sh b/padd.sh index cd14dc6..f75d3dd 100755 --- a/padd.sh +++ b/padd.sh @@ -697,7 +697,7 @@ PrintLogo() { CleanEcho "${padd_text}${dim_text}mini${reset_text} ${mini_status}" CleanEcho "" elif [ "$1" = "tiny" ]; then - CleanEcho "${padd_text}${dim_text}tiny${reset_text} Pi-hole® ${core_version_heatmap}${core_version}${reset_text}, Web ${web_version_heatmap}${web_version}${reset_text}, FTL ${ftl_version_heatmap}${ftl_version}${reset_text}" + CleanEcho "${padd_text}${dim_text}tiny${reset_text} Pi-hole® ${core_version_heatmap}${core_version}${reset_text} Web ${web_version_heatmap}${web_version}${reset_text} FTL ${ftl_version_heatmap}${ftl_version}${reset_text}" CleanPrintf " PADD ${padd_version_heatmap}${padd_version}${reset_text} ${tiny_status}${reset_text}\e[0K\\n" elif [ "$1" = "slim" ]; then CleanEcho "${padd_text}${dim_text}slim${reset_text} ${full_status}" @@ -705,13 +705,13 @@ PrintLogo() { # For the next two, use printf to make sure spaces aren't collapsed elif [ "$1" = "regular" ] || [ "$1" = "slim" ]; then CleanPrintf "${padd_logo_1}\e[0K\\n" - CleanPrintf "${padd_logo_2}Pi-hole® ${core_version_heatmap}${core_version}${reset_text}, Web ${web_version_heatmap}${web_version}${reset_text}, FTL ${ftl_version_heatmap}${ftl_version}${reset_text}\e[0K\\n" + CleanPrintf "${padd_logo_2}Pi-hole® ${core_version_heatmap}${core_version}${reset_text} Web ${web_version_heatmap}${web_version}${reset_text} FTL ${ftl_version_heatmap}${ftl_version}${reset_text}\e[0K\\n" CleanPrintf "${padd_logo_3}PADD ${padd_version_heatmap}${padd_version}${reset_text} ${full_status}${reset_text}\e[0K\\n" CleanEcho "" # normal or not defined else CleanPrintf "${padd_logo_retro_1}\e[0K\\n" - CleanPrintf "${padd_logo_retro_2} Pi-hole® ${core_version_heatmap}${core_version}${reset_text}, Web ${web_version_heatmap}${web_version}${reset_text}, FTL ${ftl_version_heatmap}${ftl_version}${reset_text}, PADD ${padd_version_heatmap}${padd_version}${reset_text}\e[0K\\n" + CleanPrintf "${padd_logo_retro_2} Pi-hole® ${core_version_heatmap}${core_version}${reset_text} Web ${web_version_heatmap}${web_version}${reset_text} FTL ${ftl_version_heatmap}${ftl_version}${reset_text} PADD ${padd_version_heatmap}${padd_version}${reset_text}\e[0K\\n" CleanPrintf "${padd_logo_retro_3} ${pihole_check_box} Core ${ftl_check_box} FTL ${mega_status}${reset_text}\e[0K\\n" CleanEcho "" From afd573e9086672d12520e7a52cefe2a9d68d48d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 19 Jul 2022 15:20:06 +0200 Subject: [PATCH 12/96] Rebase on development including new VersionConverter() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/padd.sh b/padd.sh index f75d3dd..d986e70 100755 --- a/padd.sh +++ b/padd.sh @@ -618,23 +618,23 @@ GetVersionInformation() { ftl_version="v${ftl_version}" fi - # PADD version information... - padd_version_latest="$(curl --silent https://api.github.com/repos/pi-hole/PADD/releases/latest | grep '"tag_name":' | awk -F \" '{print $4}')" - # is PADD up-to-date? - if [ -z "${padd_version_latest}" ]; then - padd_version_heatmap=${yellow_text} - else - padd_version_latest_converted="$(VersionConverter "${padd_version_latest}")" - padd_version_converted=$(VersionConverter "${padd_version}") - - if [ "${padd_version_converted}" -lt "${padd_version_latest_converted}" ]; then - padd_out_of_date_flag="true" - padd_version_heatmap=${red_text} + # PADD version information... + padd_version_latest="$(curl --silent https://api.github.com/repos/pi-hole/PADD/releases/latest | grep '"tag_name":' | awk -F \" '{print $4}')" + # is PADD up-to-date? + if [ -z "${padd_version_latest}" ]; then + padd_version_heatmap=${yellow_text} else - # local and remote PADD version match or local is newer - padd_version_heatmap=${green_text} + padd_version_latest_converted="$(VersionConverter "${padd_version_latest}")" + padd_version_converted=$(VersionConverter "${padd_version}") + + if [ "${padd_version_converted}" -lt "${padd_version_latest_converted}" ]; then + padd_out_of_date_flag="true" + padd_version_heatmap=${red_text} + else + # local and remote PADD version match or local is newer + padd_version_heatmap=${green_text} + fi fi - fi # was any portion of Pi-hole out-of-date? # yes, pi-hole is out of date From 2096d3b9c526ddd2ce5a13860f9897c5d05214e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 6 Jan 2023 21:36:04 +0100 Subject: [PATCH 13/96] Don't allow $validSession to be empty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/padd.sh b/padd.sh index d986e70..43fd979 100755 --- a/padd.sh +++ b/padd.sh @@ -128,7 +128,7 @@ Authenthication() { # Try to authenticate ChallengeResponse - while [ "${validSession}" = false ]; do + while [ "${validSession}" = false ] || [ -z "${validSession}" ] ; do echo "Authentication failed." # no password was supplied as argument From a726df6e60d63430721f3fc3b165ec15aea954ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sat, 14 Jan 2023 14:41:19 +0100 Subject: [PATCH 14/96] Mix merge mess MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 215 +++++++++++++++++++++++--------------------------------- 1 file changed, 86 insertions(+), 129 deletions(-) diff --git a/padd.sh b/padd.sh index c19ecff..2db6445 100755 --- a/padd.sh +++ b/padd.sh @@ -84,7 +84,6 @@ mega_status_hot="${check_box_bad} Your system is hot!" mega_status_off="${check_box_info} Blocking is disabled!" mega_status_ftl_down="${check_box_bad} FTLDNS service is not running!" mega_status_dns_down="${check_box_bad} Pi-hole's DNS server is off!" -mega_status_unknown="${check_box_question} Unable to determine Pi-hole status!" # TINY STATUS tiny_status_ok="${check_box_good} System is healthy" @@ -122,7 +121,7 @@ ConstructAPI() { TestAPIAvailability() { - availabilityResonse=$(curl -s -o /dev/null -w "%{http_code}" http://${URL}:${PORT}/${APIPATH}/auth) + availabilityResonse=$(curl -s -o /dev/null -w "%{http_code}" "http://${URL}:${PORT}/${APIPATH}/auth") # test if http status code was 200 (OK) if [ "${availabilityResonse}" = 200 ]; then @@ -171,7 +170,7 @@ DeleteSession() { # SID is not null (successful authenthication only), delete the session if [ "${validSession}" = true ] && [ ! "${SID}" = null ]; then # Try to delte the session. Omitt the output, but get the http status code - deleteResponse=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE http://${URL}:${PORT}/${APIPATH}/auth -H "Accept: application/json" -H "sid: ${SID}") + deleteResponse=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE "http://${URL}:${PORT}/${APIPATH}/auth" -H "Accept: application/json" -H "sid: ${SID}") case "${deleteResponse}" in "200") printf "%b" "\nA session that was not created cannot be deleted (e.g., empty API password).\n";; @@ -194,9 +193,9 @@ ChallengeResponse() { # Get challenge from FTL # Calculate response based on challenge and password hash # Send response & get session response - challenge="$(curl --silent -X GET http://${URL}:${PORT}/${APIPATH}/auth | jq --raw-output .challenge)" + challenge="$(curl --silent -X GET "http://${URL}:${PORT}/${APIPATH}/auth" | jq --raw-output .challenge)" response="$(printf "%b" "${challenge}:${pwhash}" | sha256sum | sed 's/\s.*$//')" - sessionResponse="$(curl --silent -X POST http://${URL}:${PORT}/${APIPATH}/auth --data "{\"response\":\"${response}\"}" )" + sessionResponse="$(curl --silent -X POST "http://${URL}:${PORT}/${APIPATH}/auth" --data "{\"response\":\"${response}\"}" )" if [ -z "${sessionResponse}" ]; then echo "No response from FTL server. Please check connectivity and use the options to set the API URL" @@ -222,7 +221,7 @@ GetSummaryInformation() { clients=$(echo "${summary}" | jq .ftl.clients.active ) - blocking_status=$(echo "${summary}" | jq .system.dns.blocking ) + blocking_enabled=$(echo "${summary}" | jq .system.dns.blocking ) domains_being_blocked_raw=$(echo "${summary}" | jq .ftl.database.gravity ) domains_being_blocked=$(printf "%.f" "${domains_being_blocked_raw}") @@ -246,10 +245,10 @@ GetSummaryInformation() { top_domain_raw=$(GetFTLData "/stats/top_domains" | jq --raw-output .top_domains[0].domain) - top_client_raw=$(GetFTLData "/stats/top_clients" | jq --raw-output .clients[0].name)) + top_client_raw=$(GetFTLData "/stats/top_clients" | jq --raw-output .clients[0].name) if [ -z "${top_client_raw}" ]; then # if no hostname was supplied, use IP - top_client_raw=$(GetFTLData "/stats/top_clients" | jq --raw-output .clients[0].ip)) + top_client_raw=$(GetFTLData "/stats/top_clients" | jq --raw-output .clients[0].ip) fi } @@ -260,15 +259,15 @@ GetSystemInformation() { # CPU temperature is returned in °C cpu_temp=$(echo "${summary}" | jq .system.sensors[0].value ) - # Convert CPU temperature to correct unit - if [ "${TEMPERATUREUNIT}" = "F" ]; then - temperature="$(printf %.1f "$(echo "${cpu_temp}" | awk '{print $1 * 9 / 5000 + 32}')")°F" - elif [ "${TEMPERATUREUNIT}" = "K" ]; then - temperature="$(printf %.1f "$(echo "${cpu_temp}" | awk '{print $1 / 1000 + 273.15}')")°K" - # Addresses Issue 1: https://github.com/jpmck/PAD/issues/1 - else - temperature="$(printf %.1f "$(echo "${cpu_temp}" | awk '{print $1 / 1000}')")°C" - fi + # Convert CPU temperature to correct unit + if [ "${TEMPERATUREUNIT}" = "F" ]; then + cpu_temp="$(printf %.1f "$(echo "${cpu_temp}" | awk '{print $1 * 9 / 5000 + 32}')")°F" + elif [ "${TEMPERATUREUNIT}" = "K" ]; then + cpu_temp="$(printf %.1f "$(echo "${cpu_temp}" | awk '{print $1 / 1000 + 273.15}')")°K" + # Addresses Issue 1: https://github.com/jpmck/PAD/issues/1 + else + cpu_temp="$(printf %.1f "$(echo "${cpu_temp}" | awk '{print $1 / 1000}')")°C" + fi # CPU, load, heatmap core_count=$(echo "${summary}" | jq .system.cpu.nprocs) @@ -283,13 +282,13 @@ GetSystemInformation() { # CPU temperature heatmap hot_flag=false # If we're getting close to 85°C... (https://www.raspberrypi.org/blog/introducing-turbo-mode-up-to-50-more-performance-for-free/) - if [ ${cpu_tmp} -gt 80000 ]; then + if [ "${cpu_temp}" -gt 80000 ]; then temp_heatmap=${blinking_text}${red_text} # set flag to change the status message in SetStatusMessage() hot_flag=true - elif [ ${cpu_temp} -gt 70000 ]; then + elif [ "${cpu_temp}" -gt 70000 ]; then temp_heatmap=${magenta_text} - elif [ ${cpu_temp} -gt 60000 ]; then + elif [ "${cpu_temp}" -gt 60000 ]; then temp_heatmap=${blue_text} else temp_heatmap=${cyan_text} @@ -503,12 +502,14 @@ GetPiholeInformation() { ftl_status="Running" ftl_heatmap=${green_text} ftl_check_box=${check_box_good} + # Get FTL CPU and memory usage ftl_cpu="$(ps -p "${ftlPID}" -o %cpu | tail -n1 | tr -d '[:space:]')" ftl_mem_percentage="$(ps -p "${ftlPID}" -o %mem | tail -n1 | tr -d '[:space:]')" + # Get Pi-hole (blocking) status + ftl_dns_port=$(GetFTLData "/dns/port" | jq .dns_port) fi - # Get Pi-hole (blocking) status - ftl_dns_port=$(GetFTLData "/dns/port" | jq .dns_port) + # ${ftl_dns_port} == 0 DNS server part of dnsmasq disabled, ${ftl_status} == "Not running" no ftlPID found dns_down_flag=false @@ -527,16 +528,17 @@ fi GetVersionInformation() { + out_of_date_flag=false versions_raw=$(GetFTLData "/version") # Check if core version - core_branch="$(echo "${versions_raw}" | jq --raw-output .core.branch)" - core_version=$(echo "${versions_raw}" | jq --raw-output .core.tag | tr -d '[:alpha:]' | awk -F '-' '{printf $1}') - core_version_latest=$(pihole -v -p | awk '{print $(NF)}' | tr -d ')') + CORE_BRANCH="$(echo "${versions_raw}" | jq --raw-output .core.branch)" + CORE_VERSION=$(echo "${versions_raw}" | jq --raw-output .core.tag | tr -d '[:alpha:]' | awk -F '-' '{printf $1}') + GITHUB_CORE_VERSION=$(pihole -v -p | awk '{print $(NF)}' | tr -d ')') + CORE_HASH + GITHUB_CORE_HASH - out_of_date_flag=false - - # Gather CORE version information... + # Gather core version information... # Extract vx.xx or vx.xx.xxx version CORE_VERSION="$(echo "${CORE_VERSION}" | grep -oE '^v[0-9]+([.][0-9]+){1,2}')" if [ "${CORE_BRANCH}" = "master" ]; then @@ -576,6 +578,9 @@ GetVersionInformation() { if [ "$INSTALL_WEB_INTERFACE" = true ]; then WEB_BRANCH="$(echo "${versions_raw}" | jq --raw-output .web.branch)" WEB_VERSION=$(echo "${versions_raw}" | jq --raw-output .web.tag | tr -d '[:alpha:]' | awk -F '-' '{printf $1}') + GITHUB_WEB_VERSION + WEB_HASH + GITHUB_WEB_HASH if [ "${WEB_BRANCH}" = "master" ]; then web_version_converted="$(VersionConverter "${WEB_VERSION}")" @@ -618,6 +623,10 @@ GetVersionInformation() { # Extract vx.xx or vx.xx.xxx version FTL_BRANCH="$(echo "${versions_raw}" | jq --raw-output .ftl.branch)" FTL_VERSION=$(echo "${versions_raw}" | jq --raw-output .ftl.tag | tr -d '[:alpha:]' | awk -F '-' '{printf $1}') + GITHUB_FTL_VERSION + FTL_HASH + GITHUB_FTL_HASH + if [ "${FTL_BRANCH}" = "master" ]; then ftl_version_converted="$(VersionConverter "${FTL_VERSION}")" @@ -750,10 +759,10 @@ SetStatusMessage() { if [ "${hot_flag}" = true ]; then # Check if CPU temperature is high pico_status="${pico_status_hot}" - mini_status="${mini_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" - tiny_status="${tiny_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" - full_status="${full_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" - mega_status="${mega_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" + mini_status="${mini_status_hot} ${blinking_text}${red_text}${cpu_temp}${reset_text}" + tiny_status="${tiny_status_hot} ${blinking_text}${red_text}${cpu_temp}${reset_text}" + full_status="${full_status_hot} ${blinking_text}${red_text}${cpu_temp}${reset_text}" + mega_status="${mega_status_hot} ${blinking_text}${red_text}${cpu_temp}${reset_text}" elif [ "${ftl_down_flag}" = true ]; then # Check if FTL is down @@ -771,15 +780,7 @@ SetStatusMessage() { full_status=${full_status_dns_down} mega_status=${mega_status_dns_down} - elif [ "${blocking_status}" = "unknown" ]; then - # Check if blocking status is unknown - pico_status=${pico_status_unknown} - mini_status=${mini_status_unknown} - tiny_status=${tiny_status_unknown} - full_status=${full_status_unknown} - mega_status=${mega_status_unknown} - - elif [ "${blocking_status}" = "disabled" ]; then + elif [ "${blocking_enabled}" = "false" ]; then # Check if blocking status is disabled pico_status=${pico_status_off} mini_status=${mini_status_off} @@ -795,7 +796,7 @@ SetStatusMessage() { full_status=${full_status_update} mega_status=${mega_status_update} - elif [ "${blocking_status}" = "enabled" ]; then + elif [ "${blocking_enabled}" = "true" ]; then # if we reach this point and blocking is enabled, everything is fine pico_status=${pico_status_ok} mini_status=${mini_status_ok} @@ -936,7 +937,7 @@ PrintDashboard() { fi moveXOffset; printf "%s${clear_line}\n" "${bold_text}SYSTEM ==============================================${reset_text}" moveXOffset; printf " %-10s%-29s${clear_line}\n" "Uptime:" "${system_uptime}" - moveXOffset; printf " %-10s${temp_heatmap}%-17s${reset_text} %-8s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-4s${reset_text}${clear_line}\n" "CPU Temp:" "${temperature}" "Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" + moveXOffset; printf " %-10s${temp_heatmap}%-17s${reset_text} %-8s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-4s${reset_text}${clear_line}\n" "CPU Temp:" "${cpu_temp}" "Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" moveXOffset; printf " %-10s[${memory_heatmap}%-7s${reset_text}] %-6s %-8s[${cpu_load_1_heatmap}%-7s${reset_text}] %-5s${clear_line}" "Memory:" "${memory_bar}" "${memory_percent}%" "CPU:" "${cpu_bar}" "${cpu_percent}%" elif [ "$1" = "regular" ] || [ "$1" = "slim" ]; then # slim is a screen with at least 60 columns and exactly 21 lines @@ -973,7 +974,7 @@ PrintDashboard() { fi moveXOffset; printf "%s${clear_line}\n" "${bold_text}SYSTEM =====================================================${reset_text}" moveXOffset; printf " %-10s%-39s${clear_line}\n" "Uptime:" "${system_uptime}" - moveXOffset; printf " %-10s${temp_heatmap}%-21s${reset_text}%-10s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-4s${reset_text}${clear_line}\n" "CPU Temp:" "${temperature}" "CPU Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" + moveXOffset; printf " %-10s${temp_heatmap}%-21s${reset_text}%-10s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-4s${reset_text}${clear_line}\n" "CPU Temp:" "${cpu_temp}" "CPU Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" moveXOffset; printf " %-10s[${memory_heatmap}%-10s${reset_text}] %-6s %-10s[${cpu_load_1_heatmap}%-10s${reset_text}] %-5s${clear_line}" "Memory:" "${memory_bar}" "${memory_percent}%" "CPU Load:" "${cpu_bar}" "${cpu_percent}%" else # ${padd_size} = mega # mega is a screen with at least 80 columns and 26 lines @@ -990,7 +991,7 @@ PrintDashboard() { moveXOffset; printf " %-10s%-39s${clear_line}\n" "Top Clnt:" "${top_client}" moveXOffset; printf "%s${clear_line}\n" "${bold_text}FTL ============================================================================${reset_text}" moveXOffset; printf " %-10s%-9s %-10s%-9s %-10s%-9s${clear_line}\n" "PID:" "${ftlPID}" "CPU Use:" "${ftl_cpu}" "Mem. Use:" "${ftl_mem_percentage}" - moveXOffset; printf " %-10s%-69s${clear_line}\n" "DNSCache:" "${cache_inserts} insertions, ${cache_deletes} deletions, ${cache_size} total entries" + moveXOffset; printf " %-10s%-69s${clear_line}\n" "DNSCache:" "${cache_inserts} insertions, ${cache_evictions} deletions, ${cache_size} total entries" moveXOffset; printf "%s${clear_line}\n" "${bold_text}NETWORK ========================================================================${reset_text}" moveXOffset; printf " %-10s%-19s${clear_line}\n" "Hostname:" "${full_hostname}" moveXOffset; printf " %-10s%-15s %-4s%-9s %-4s%-9s${clear_line}\n" "Interfce:" "${iface_name}" "TX:" "${tx_bytes}" "RX:" "${rx_bytes}" @@ -1002,7 +1003,7 @@ PrintDashboard() { moveXOffset; printf "%s${clear_line}\n" "${bold_text}SYSTEM =========================================================================${reset_text}" moveXOffset; printf " %-10s%-39s${clear_line}\n" "Device:" "${sys_model}" moveXOffset; printf " %-10s%-39s %-10s[${memory_heatmap}%-10s${reset_text}] %-6s${clear_line}\n" "Uptime:" "${system_uptime}" "Memory:" "${memory_bar}" "${memory_percent}%" - moveXOffset; printf " %-10s${temp_heatmap}%-10s${reset_text} %-10s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-7s${reset_text} %-10s[${memory_heatmap}%-10s${reset_text}] %-6s${clear_line}" "CPU Temp:" "${temperature}" "CPU Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" "CPU Load:" "${cpu_bar}" "${cpu_percent}%" + moveXOffset; printf " %-10s${temp_heatmap}%-10s${reset_text} %-10s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-7s${reset_text} %-10s[${memory_heatmap}%-10s${reset_text}] %-6s${clear_line}" "CPU Temp:" "${cpu_temp}" "CPU Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" "CPU Load:" "${cpu_bar}" "${cpu_percent}%" fi # Clear to end of screen (below the drawn dashboard) @@ -1152,6 +1153,7 @@ SizeChecker(){ fi fi } + # converts a given version string e.g. v3.7.1 to 3007001000 to allow for easier comparison of multi digit version numbers # credits https://apple.stackexchange.com/a/123408 VersionConverter() { @@ -1178,6 +1180,7 @@ moveXOffset(){ if [ "${xOffset}" -gt 0 ]; then printf '\e[%sC' "${xOffset}" fi +} # Remove undesired strings from sys_model variable - used in GetSystemInformation() function filterModel() { @@ -1216,7 +1219,7 @@ truncateString() { OutputJSON() { # Traps for graceful shutdown # https://unix.stackexchange.com/a/681201 - trap clean_exit EXIT + trap CleanExit EXIT trap sig_cleanup INT QUIT TERM # Save current terminal settings (needed for later restore after password prompt) @@ -1235,8 +1238,6 @@ OutputJSON() { } StartupRoutine(){ - # Get config variables - . /etc/pihole/setupVars.conf # Clear the screen and move cursor to (0,0). # This mimics the 'clear' command. @@ -1248,9 +1249,6 @@ StartupRoutine(){ # adds the y-offset moveYOffset - # Get versions information - . /etc/pihole/versions - if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then moveXOffset; PrintLogo "$1" moveXOffset; printf "%b" "START-UP ===========\n" @@ -1378,7 +1376,6 @@ NormalPADD() { # Get uptime, CPU load, temp, etc. every 5 seconds if [ $((now - LastCheckSystemInformation)) -ge 5 ]; then - . /etc/pihole/setupVars.conf GetSystemInformation LastCheckSystemInformation="${now}" fi @@ -1389,12 +1386,6 @@ NormalPADD() { LastCheckSummaryInformation="${now}" fi - # Get uptime, CPU load, temp, etc. every 5 seconds - if [ $((now - LastCheckSystemInformation)) -ge 5 ]; then - GetSystemInformation ${padd_size} - LastCheckSystemInformation="${now}" - fi - # Get FTL status every 5 seconds if [ $((now - LastCheckPiholeInformation)) -ge 5 ]; then GetPiholeInformation @@ -1409,7 +1400,6 @@ NormalPADD() { # Get Pi-hole components version information every 30 seconds if [ $((now - LastCheckVersionInformation)) -ge 30 ]; then - . /etc/pihole/versions GetVersionInformation LastCheckVersionInformation="${now}" fi @@ -1421,8 +1411,6 @@ NormalPADD() { fi done - - DeleteSession } DisplayHelp() { @@ -1435,15 +1423,16 @@ DisplayHelp() { ::: -xoff [num] set the x-offset, reference is the upper left corner, disables auto-centering ::: -yoff [num] set the y-offset, reference is the upper left corner, disables auto-centering ::: -::: -u URL or address of your Pi-hole (default: pi.hole) -::: -p Port of your Pi-hole's API (default: 8080) -::: -a Path where your Pi-hole's API is hosted (default: api) -::: -s Your Pi-hole's password, required to access the API -::: -j output stats as JSON formatted string and exit and exit -::: -h display this help text +::: -u URL or address of your Pi-hole (default: pi.hole) +::: -p Port of your Pi-hole's API (default: 8080) +::: -a Path where your Pi-hole's API is hosted (default: api) +::: -s Your Pi-hole's password, required to access the API +::: -j output stats as JSON formatted string and exit and exit +::: -h display this help text EOM - exit 0 + # exit with the supplied argument + exit "$1" } # Called on signals INT QUIT TERM @@ -1455,12 +1444,12 @@ sig_cleanup() { # causing EXIT trap to be executed, so we trap EXIT after INT trap '' EXIT - (exit $err) # execute in a subshell just to pass $? to clean_exit() - clean_exit + (exit $err) # execute in a subshell just to pass $? to CleanExit() + CleanExit } # Called on signal EXIT, or indirectly on INT QUIT TERM -clean_exit() { +CleanExit() { # save the return code of the script err=$? @@ -1472,58 +1461,16 @@ clean_exit() { stty "${stty_orig}" fi - # Turn cursor on - setterm -cursor on - - # Delete session from FTL server - DeleteSession - exit $err # exit the script with saved $? -} - -# Get supplied options - -while getopts ":u:p:a:s:jh" args; do - case "${args}" in - u) URL="${OPTARG}" ;; - p) PORT="${OPTARG}" ;; - a) APIPATH="${OPTARG}" ;; - s) password="${OPTARG}" ;; - j) OutputJSON;; - h) DisplayHelp;; - \?) echo "Invalid option: -${OPTARG}" - exit 1 ;; - :) echo "Option -$OPTARG requires an argument." - exit 1 ;; - *) DisplayHelp;; - esac -done - -# Save current terminal settings (needed for later restore after password prompt) -stty_orig=$(stty -g) - -# Turns off the cursor -# (From Pull request #8 https://github.com/jpmck/PADD/pull/8) -setterm -cursor off - -# Construct FTL's API address depending on the arguments supplied -ConstructAPI - -# Test if the authentication endpoint is availabe -TestAPIAvailability - -# Traps for graceful shutdown -# https://unix.stackexchange.com/a/681201 -trap clean_exit EXIT -trap sig_cleanup INT QUIT TERM - # Show the cursor # https://vt100.net/docs/vt510-rm/DECTCEM.html printf '\e[?25h' # if background sleep is running, kill it # http://mywiki.wooledge.org/SignalTrap#When_is_the_signal_handled.3F - kill $sleepPID > /dev/null 2>&1 + kill "{$sleepPID}" > /dev/null 2>&1 + # Delete session from FTL server + DeleteSession exit $err # exit the script with saved $? } @@ -1541,23 +1488,29 @@ TerminalResize(){ printf '\e[H\e[2J\e[3J' - kill $sleepPID > /dev/null 2>&1 + kill "{$sleepPID}" > /dev/null 2>&1 } main(){ + # Hiding the cursor. # https://vt100.net/docs/vt510-rm/DECTCEM.html printf '\e[?25l' - # Trap on exit - trap 'CleanExit' INT TERM EXIT + # Traps for graceful shutdown + # https://unix.stackexchange.com/a/681201 + trap CleanExit EXIT + trap sig_cleanup INT QUIT TERM - # If setupVars.conf is not present, then PADD is not running on a Pi-hole - # and we are not able to start as StartupRoutine() will fail below - if [ ! -f /etc/pihole/setupVars.conf ]; then - printf "%b" "${check_box_bad} Error!\n PADD only works in conjunction with Pi-hole!\n" - exit 1 - fi + # Save current terminal settings (needed for later restore after password prompt) + stty_orig=$(stty -g) + + + # Construct FTL's API address depending on the arguments supplied + ConstructAPI + + # Test if the authentication endpoint is availabe + TestAPIAvailability SizeChecker @@ -1570,11 +1523,15 @@ main(){ # Process all options (if present) while [ "$#" -gt 0 ]; do case "$1" in - "-j" | "--json" ) OutputJSON; exit 0;; - "-h" | "--help" ) DisplayHelp; exit 0;; + "-j" | "--json" ) OutputJSON;; + "-h" | "--help" ) DisplayHelp "0";; "-xoff" ) xOffset="$2"; xOffOrig="$2"; shift;; "-yoff" ) yOffset="$2"; yOffOrig="$2"; shift;; - * ) DisplayHelp; exit 1;; + "-u" ) URL="$2"; shift;; + "-p" ) PORT="$2"; shift;; + "-a" ) APIPATH="$2"; shift;; + "-s" ) password="$2"; shift;; + * ) DisplayHelp "1";; esac shift done From 70e33c1014cda6ca3013303c1b7b853ceaab0263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sat, 14 Jan 2023 20:03:40 +0100 Subject: [PATCH 15/96] Adjust to current FTL endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 674 +++++++++++++++++++++++++++----------------------------- 1 file changed, 325 insertions(+), 349 deletions(-) diff --git a/padd.sh b/padd.sh index 2db6445..0245cb0 100755 --- a/padd.sh +++ b/padd.sh @@ -28,9 +28,6 @@ LastCheckPiholeInformation=$(date +%s) LastCheckSystemInformation=$(date +%s) LastCheckPADDInformation=$(date +%s) -# CORES -core_count=$(nproc --all 2> /dev/null) - # COLORS CSI="$(printf '\033')[" # Control Sequence Introducer red_text="${CSI}91m" # Red @@ -125,10 +122,10 @@ TestAPIAvailability() { # test if http status code was 200 (OK) if [ "${availabilityResonse}" = 200 ]; then - printf "%b" "API available at: http://${URL}:${PORT}/${APIPATH}\n" + moveXOffset; printf "%b" "API available at: http://${URL}:${PORT}/${APIPATH}\n" else - echo "API not available at: http://${URL}:${PORT}/${APIPATH}" - echo "Exiting." + moveXOffset; echo "API not available at: http://${URL}:${PORT}/${APIPATH}" + moveXOffset; echo "Exiting." exit 1 fi } @@ -138,13 +135,13 @@ Authenthication() { ChallengeResponse while [ "${validSession}" = false ] || [ -z "${validSession}" ] ; do - echo "Authentication failed." + moveXOffset; echo "Authentication failed." # no password was supplied as argument if [ -z "${password}" ]; then - echo "No password supplied. Please enter your password:" + moveXOffset; echo "No password supplied. Please enter your password:" else - echo "Wrong password supplied, please enter the correct password:" + moveXOffset; echo "Wrong password supplied, please enter the correct password:" fi # POSIX's `read` does not support `-s` option (suppressing the input) @@ -161,7 +158,7 @@ Authenthication() { done # Loop exited, authentication was successful - echo "Authentication successful." + moveXOffset; echo "Authentication successful." } @@ -172,10 +169,11 @@ DeleteSession() { # Try to delte the session. Omitt the output, but get the http status code deleteResponse=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE "http://${URL}:${PORT}/${APIPATH}/auth" -H "Accept: application/json" -H "sid: ${SID}") + printf "\n\n" case "${deleteResponse}" in - "200") printf "%b" "\nA session that was not created cannot be deleted (e.g., empty API password).\n";; - "401") printf "%b" "\nLogout attempt without a valid session. Unauthorized!\n";; - "410") printf "%b" "\n\nSession successfully deleted.\n";; + "200") moveXOffset; printf "%b" "A session that was not created cannot be deleted (e.g., empty API password).\n";; + "401") moveXOffset; printf "%b" "Logout attempt without a valid session. Unauthorized!\n";; + "410") moveXOffset; printf "%b" "Session successfully deleted.\n";; esac; fi @@ -198,8 +196,8 @@ ChallengeResponse() { sessionResponse="$(curl --silent -X POST "http://${URL}:${PORT}/${APIPATH}/auth" --data "{\"response\":\"${response}\"}" )" if [ -z "${sessionResponse}" ]; then - echo "No response from FTL server. Please check connectivity and use the options to set the API URL" - echo "Usage: $0 [-u ] [-p ] [-a ] " + moveXOffset; echo "No response from FTL server. Please check connectivity and use the options to set the API URL" + moveXOffset; echo "Usage: $0 [-u ] [-p ] [-a ] " exit 1 fi # obtain validity and session ID from session response @@ -218,12 +216,14 @@ GetFTLData() { GetSummaryInformation() { summary=$(GetFTLData "/stats/summary") cache_info=$(GetFTLData "/dns/cache") + sysinfo=$(GetFTLData "/ftl/sysinfo") + dns_blocking=$(GetFTLData "/dns/blocking") - clients=$(echo "${summary}" | jq .ftl.clients.active ) + clients=$(echo "${sysinfo}" | jq .ftl.clients.active ) - blocking_enabled=$(echo "${summary}" | jq .system.dns.blocking ) + blocking_enabled=$(echo "${dns_blocking}" | jq .blocking ) - domains_being_blocked_raw=$(echo "${summary}" | jq .ftl.database.gravity ) + domains_being_blocked_raw=$(echo "${sysinfo}" | jq .ftl.database.gravity) domains_being_blocked=$(printf "%.f" "${domains_being_blocked_raw}") dns_queries_today_raw=$(echo "$summary" | jq .queries.total ) @@ -235,15 +235,15 @@ GetSummaryInformation() { ads_percentage_today_raw=$(echo "$summary" | jq .queries.percent_blocked) ads_percentage_today=$(printf "%.1f" "${ads_percentage_today_raw}") - cache_size=$(echo "$cache_info" | jq .size) - cache_evictions=$(echo "$cache_info" | jq .evicted) - cache_inserts=$(echo "$cache_info"| jq .inserted) + cache_size=$(echo "$cache_info" | jq .cache.size) + cache_evictions=$(echo "$cache_info" | jq .cache.evicted) + cache_inserts=$(echo "$cache_info"| jq .cache.inserted) latest_blocked_raw=$(GetFTLData "/stats/recent_blocked?show=1" | jq --raw-output .blocked[0]) - top_blocked_raw=$(GetFTLData "/stats/top_blocked" | jq --raw-output .top_domains[0].domain) + top_blocked_raw=$(GetFTLData "/stats/top_domains?blocked=true" | jq --raw-output .domains[0].domain) - top_domain_raw=$(GetFTLData "/stats/top_domains" | jq --raw-output .top_domains[0].domain) + top_domain_raw=$(GetFTLData "/stats/top_domains" | jq --raw-output .domains[0].domain) top_client_raw=$(GetFTLData "/stats/top_clients" | jq --raw-output .clients[0].name) if [ -z "${top_client_raw}" ]; then @@ -253,242 +253,210 @@ GetSummaryInformation() { } GetSystemInformation() { + sysinfo=$(GetFTLData "/ftl/sysinfo") + # System uptime - system_uptime_raw=$(echo "${summary}" | jq .system.uptime ) + system_uptime_raw=$(echo "${sysinfo}" | jq .system.uptime ) - # CPU temperature is returned in °C - cpu_temp=$(echo "${summary}" | jq .system.sensors[0].value ) + # CPU temperature and unit + cpu_temp_raw=$(echo "${sysinfo}" | jq .system.sensors[0].value) + cpu_temp=$(printf "%.1f" "${cpu_temp_raw}") + temp_unit=$(echo "${sysinfo}" | jq --raw-output .system.sensors[0].unit) - # Convert CPU temperature to correct unit - if [ "${TEMPERATUREUNIT}" = "F" ]; then - cpu_temp="$(printf %.1f "$(echo "${cpu_temp}" | awk '{print $1 * 9 / 5000 + 32}')")°F" - elif [ "${TEMPERATUREUNIT}" = "K" ]; then - cpu_temp="$(printf %.1f "$(echo "${cpu_temp}" | awk '{print $1 / 1000 + 273.15}')")°K" - # Addresses Issue 1: https://github.com/jpmck/PAD/issues/1 + # Temp + Unit + if [ "${temp_unit}" = "C" ]; then + temperature="${cpu_temp}°${temp_unit}" + # no conversion needed + cpu_temp_celsius="$(echo "${cpu_temp}" | awk -F '.' '{print $1}')" + elif [ "${temp_unit}" = "F" ]; then + temperature="${cpu_temp}°${temp_unit}" + # convert to Celsius for limit checking + cpu_temp_celsius="$(echo "${cpu_temp}" | awk '{print ($1-32) * 5 / 9}' | awk -F '.' '{print $1}')" + elif [ "${temp_unit}" = "K" ]; then + # no ° for Kelvin + temperature="${cpu_temp}${temp_unit}" + # convert to Celsius for limit checking + cpu_temp_celsius="$(echo "${cpu_temp}" | awk '{print $1 - 273.15}' | awk -F '.' '{print $1}')" + fi + + # CPU temperature heatmap + hot_flag=false + # If we're getting close to 85°C... (https://www.raspberrypi.org/blog/introducing-turbo-mode-up-to-50-more-performance-for-free/) + if [ "${cpu_temp_celsius}" -gt 80 ]; then + temp_heatmap=${blinking_text}${red_text} + # set flag to change the status message in SetStatusMessage() + hot_flag=true + elif [ "${cpu_temp_celsius}" -gt 70 ]; then + temp_heatmap=${magenta_text} + elif [ "${cpu_temp_celsius}" -gt 60 ]; then + temp_heatmap=${blue_text} else - cpu_temp="$(printf %.1f "$(echo "${cpu_temp}" | awk '{print $1 / 1000}')")°C" + temp_heatmap=${cyan_text} fi # CPU, load, heatmap - core_count=$(echo "${summary}" | jq .system.cpu.nprocs) - cpu_load_1=$(printf %.2f "$(echo "${summary}" | jq .system.cpu.load.raw[0])") - cpu_load_5=$(printf %.2f "$(echo "${summary}" | jq .system.cpu.load.raw[1])") - cpu_load_15=$(printf %.2f "$(echo "${summary}" | jq .system.cpu.load.raw[2])") + core_count=$(echo "${sysinfo}" | jq .system.cpu.nprocs) + cpu_load_1=$(printf %.2f "$(echo "${sysinfo}" | jq .system.cpu.load.raw[0])") + cpu_load_5=$(printf %.2f "$(echo "${sysinfo}" | jq .system.cpu.load.raw[1])") + cpu_load_15=$(printf %.2f "$(echo "${sysinfo}" | jq .system.cpu.load.raw[2])") cpu_load_1_heatmap=$(HeatmapGenerator "${cpu_load_1}" "${core_count}") cpu_load_5_heatmap=$(HeatmapGenerator "${cpu_load_5}" "${core_count}") cpu_load_15_heatmap=$(HeatmapGenerator "${cpu_load_15}" "${core_count}") - cpu_percent=$(printf %.1f "$(echo "${summary}" | jq .system.cpu.load.percent[0])") + cpu_percent=$(printf %.1f "$(echo "${sysinfo}" | jq .system.cpu.load.percent[0])") - # CPU temperature heatmap - hot_flag=false - # If we're getting close to 85°C... (https://www.raspberrypi.org/blog/introducing-turbo-mode-up-to-50-more-performance-for-free/) - if [ "${cpu_temp}" -gt 80000 ]; then - temp_heatmap=${blinking_text}${red_text} - # set flag to change the status message in SetStatusMessage() - hot_flag=true - elif [ "${cpu_temp}" -gt 70000 ]; then - temp_heatmap=${magenta_text} - elif [ "${cpu_temp}" -gt 60000 ]; then - temp_heatmap=${blue_text} - else - temp_heatmap=${cyan_text} - fi + # Memory use, heatmap and bar + memory_percent="$(echo "${sysinfo}" | jq '.system.memory.ram."%used"')" + memory_heatmap="$(HeatmapGenerator "${memory_percent}")" - # Memory use, heatmap and bar - memory_total=$(echo "${summary}" | jq .system.memory.ram.total) - memory_available=$(echo "${summary}" | jq .system.memory.ram.available) - memory_percent=$(printf %.1f $(((memory_total-memory_available)*100/memory_total)) ) - memory_heatmap=$(HeatmapGenerator "${memory_percent}") + # Get device model + sys_model="$(echo "${sysinfo}" | jq --raw-output .system.model)" - # Get product name and family - product_name= - product_family= - if [ -f /sys/devices/virtual/dmi/id/product_name ]; then - # Get product name, remove possible null byte - product_name=$(tr -d '\0' < /sys/devices/virtual/dmi/id/product_name) - fi - if [ -f /sys/devices/virtual/dmi/id/product_family ]; then - # Get product family, remove possible null byte - product_family=$(tr -d '\0' < /sys/devices/virtual/dmi/id/product_family) - fi - - board_vendor= - board_name= - if [ -f /sys/devices/virtual/dmi/id/board_vendor ]; then - board_vendor=$(tr -d '\0' < /sys/devices/virtual/dmi/id/board_vendor) - fi - if [ -f /sys/devices/virtual/dmi/id/board_name ]; then - board_name="$(tr -d '\0' < /sys/devices/virtual/dmi/id/board_name)" - fi - - - if [ -n "$product_name" ] || [ -n "$product_family" ]; then - if echo "$product_family" | grep -q "$product_name"; then - # If product_name is contained in product_family, only show product_family - sys_model="${product_family}" - else - # If product_name is not contained in product_family, both are shown - sys_model="${product_family} ${product_name}" + # DOCKER_VERSION is set during GetVersionInformation, so this needs to run first during startup + if [ -n "${DOCKER_VERSION}" ] && [ ! "${DOCKER_VERSION}" = "null" ]; then + # Docker image + sys_model="Docker tag ${DOCKER_VERSION}" fi - elif [ -f /sys/firmware/devicetree/base/model ]; then - sys_model=$(tr -d '\0' < /sys/firmware/devicetree/base/model) - elif [ -n "$board_vendor" ] || [ -n "$board_name" ]; then - sys_model="${board_vendor} ${board_name}" - elif [ -f /tmp/sysinfo/model ]; then - sys_model=$(tr -d '\0' < /tmp/sysinfo/model) - elif [ -n "${DOCKER_VERSION}" ]; then - # Docker image. DOCKER_VERSION is read from /etc/pihole/versions - sys_model="Docker tag ${DOCKER_VERSION}" - fi - # Cleaning device model from useless OEM information - sys_model=$(filterModel "${sys_model}") + # Cleaning device model from useless OEM information + sys_model=$(filterModel "${sys_model}") - if [ -z "$sys_model" ]; then - sys_model="Unknown" - fi + if [ -z "$sys_model" ]; then + sys_model="Unknown" + fi } GetNetworkInformation() { - interfaces_raw=$(GetFTLData "/ftl/interfaces") + interfaces_raw=$(GetFTLData "/network/interfaces") + sysinfo=$(GetFTLData "/ftl/sysinfo") + config=$(GetFTLData "/config") + # Get pi IPv4 address of the default interface - pi_ip4_addrs="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].ipv4 | sed "s/127.0.0.1,//g" | tr "," " " | wc -w)" + pi_ip4_addrs="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv4[]' | wc -w)" if [ "${pi_ip4_addrs}" -eq 0 ]; then # No IPv4 address available pi_ip4_addr="N/A" elif [ "${pi_ip4_addrs}" -eq 1 ]; then # One IPv4 address available - pi_ip4_addr="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].ipv4 | sed "s/127.0.0.1,//g" | awk -F ',' '{printf $1}')" + pi_ip4_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv4[0]')" else # More than one IPv4 address available - pi_ip4_addr="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].ipv4 | sed "s/127.0.0.1,//g"| awk -F ',' '{printf $1}')+" + pi_ip4_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv4[0]')+" fi - # Get pi IPv6 address of the default interface - pi_ip6_addrs="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].ipv6 | sed "s/::1,//g" | tr "," " " | wc -w)" - if [ "${pi_ip6_addrs}" -eq 0 ]; then - # No IPv6 address available - pi_ip6_addr="N/A" - ipv6_check_box=${check_box_bad} - elif [ "${pi_ip6_addrs}" -eq 1 ]; then - # One IPv6 address available - pi_ip6_addr="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].ipv6 | sed "s/::1,//g" | awk -F ',' '{printf $1}')" - ipv6_check_box=${check_box_good} - else - # More than one IPv6 address available - pi_ip6_addr="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].ipv6 | sed "s/::1,//g" | awk -F ',' '{printf $1}')+" - ipv6_check_box=${check_box_good} - fi - - # Get hostname and gateway - pi_hostname=$(hostname) - - full_hostname=${pi_hostname} - # does the Pi-hole have a domain set? - if [ -n "${PIHOLE_DOMAIN+x}" ]; then - # is Pi-hole acting as DHCP server? - if [ "${DHCP_ACTIVE}" = "true" ]; then - count=${pi_hostname}"."${PIHOLE_DOMAIN} - count=${#count} - if [ "${count}" -lt "18" ]; then - full_hostname=${pi_hostname}"."${PIHOLE_DOMAIN} - fi - fi - fi - - # Get the DNS count (from pihole -c) - dns_count="0" - [ -n "${PIHOLE_DNS_1}" ] && dns_count=$((dns_count+1)) - [ -n "${PIHOLE_DNS_2}" ] && dns_count=$((dns_count+1)) - [ -n "${PIHOLE_DNS_3}" ] && dns_count=$((dns_count+1)) - [ -n "${PIHOLE_DNS_4}" ] && dns_count=$((dns_count+1)) - [ -n "${PIHOLE_DNS_5}" ] && dns_count=$((dns_count+1)) - [ -n "${PIHOLE_DNS_6}" ] && dns_count=$((dns_count+1)) - [ -n "${PIHOLE_DNS_7}" ] && dns_count=$((dns_count+1)) - [ -n "${PIHOLE_DNS_8}" ] && dns_count=$((dns_count+1)) - [ -n "${PIHOLE_DNS_9}" ] && dns_count=$((dns_count+1)) - - # if there's only one DNS server - if [ ${dns_count} -eq 1 ]; then - dns_information="1 server" - else - dns_information="${dns_count} servers" - fi - - # Is Pi-Hole acting as the DHCP server? - if [ "${DHCP_ACTIVE}" = "true" ]; then - dhcp_status="Enabled" - dhcp_info=" Range: ${DHCP_START} - ${DHCP_END}" - dhcp_heatmap=${green_text} - dhcp_check_box=${check_box_good} - - # Is DHCP handling IPv6? - # DHCP_IPv6 is set in setupVars.conf - # shellcheck disable=SC2154 - if [ "${DHCP_IPv6}" = "true" ]; then - dhcp_ipv6_status="Enabled" - dhcp_ipv6_heatmap=${green_text} - dhcp_ipv6_check_box=${check_box_good} + # Get pi IPv6 address of the default interface + pi_ip6_addrs="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv6[]' | wc -w)" + if [ "${pi_ip6_addrs}" -eq 0 ]; then + # No IPv6 address available + pi_ip6_addr="N/A" + ipv6_check_box=${check_box_bad} + elif [ "${pi_ip6_addrs}" -eq 1 ]; then + # One IPv6 address available + pi_ip6_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv6[0]' | cut -f1 -d "%" )" + ipv6_check_box=${check_box_good} else - dhcp_ipv6_status="Disabled" - dhcp_ipv6_heatmap=${red_text} - dhcp_ipv6_check_box=${check_box_bad} - fi - else - dhcp_status="Disabled" - dhcp_heatmap=${red_text} - dhcp_check_box=${check_box_bad} - - # if the DHCP Router variable isn't set - if [ -z ${DHCP_ROUTER+x} ]; then - DHCP_ROUTER=$(printf %b "${interfaces_raw}" | jq --raw-output .gateway.address) + # More than one IPv6 address available + pi_ip6_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv6[0]' | cut -f1 -d "%" )+" + ipv6_check_box=${check_box_good} fi - dhcp_info=" Router: ${DHCP_ROUTER}" - dhcp_heatmap=${red_text} - dhcp_check_box=${check_box_bad} + # Is Pi-Hole acting as the DHCP server? + DHCP_ACTIVE="$(echo "${config}" | jq .config.dnsmasq.dhcp.active)" - dhcp_ipv6_status="N/A" - dhcp_ipv6_heatmap=${yellow_text} - dhcp_ipv6_check_box=${check_box_question} - fi + if [ "${DHCP_ACTIVE}" = "true" ]; then + DHCP_START="$(echo "${config}" | jq --raw-output .config.dnsmasq.dhcp.start)" + DHCP_END="$(echo "${config}" | jq --raw-output .config.dnsmasq.dhcp.end)" - # DNSSEC - if [ "${DNSSEC}" = "true" ]; then - dnssec_status="Enabled" - dnssec_heatmap=${green_text} - else - dnssec_status="Disabled" - dnssec_heatmap=${red_text} - fi + dhcp_status="Enabled" + dhcp_info=" Range: ${DHCP_START} - ${DHCP_END}" + dhcp_heatmap=${green_text} + dhcp_check_box=${check_box_good} - # Conditional forwarding - if [ "${CONDITIONAL_FORWARDING}" = "true" ] || [ "${REV_SERVER}" = "true" ]; then - conditional_forwarding_status="Enabled" - conditional_forwarding_heatmap=${green_text} - else - conditional_forwarding_status="Disabled" - conditional_forwarding_heatmap=${red_text} - fi + # Is DHCP handling IPv6? + DHCP_IPv6="$(echo "${config}" | jq --raw-output .config.dnsmasq.dhcp.ipv6)" + if [ "${DHCP_IPv6}" = "true" ]; then + dhcp_ipv6_status="Enabled" + dhcp_ipv6_heatmap=${green_text} + dhcp_ipv6_check_box=${check_box_good} + else + dhcp_ipv6_status="Disabled" + dhcp_ipv6_heatmap=${red_text} + dhcp_ipv6_check_box=${check_box_bad} + fi + else + dhcp_status="Disabled" + dhcp_heatmap=${red_text} + dhcp_check_box=${check_box_bad} - #Default interface data - iface_name="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].name)" - tx_bytes="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].tx.num)" - tx_bytes_unit="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].tx.unit)" + GATEWAY="$(GetFTLData "/network/gateway" | jq --raw-output .address)" + dhcp_info=" Router: ${GATEWAY}" + dhcp_ipv6_status="N/A" + dhcp_ipv6_heatmap=${yellow_text} + dhcp_ipv6_check_box=${check_box_question} + fi + + # Get hostname + pi_hostname="$(echo "${sysinfo}" | jq --raw-output .system.uname.nodename)" + full_hostname=${pi_hostname} + # when PI-hole is the DHCP server, append the domain to the hostname + if [ "${DHCP_ACTIVE}" = "true" ]; then + PIHOLE_DOMAIN="$(echo "${config}" | jq --raw-output .config.dnsmasq.domain)" + if [ -n "${PIHOLE_DOMAIN}" ]; then + count=${pi_hostname}"."${PIHOLE_DOMAIN} + count=${#count} + if [ "${count}" -lt "18" ]; then + full_hostname=${pi_hostname}"."${PIHOLE_DOMAIN} + fi + fi + fi + + # Get the number of configured upstream DNS servers + dns_count="$(echo "${config}" | jq --raw-output .config.dnsmasq.upstreams[] | sed '/^\s*$/d' | wc -l)" + # if there's only one DNS server + if [ "${dns_count}" -eq 1 ]; then + dns_information="1 server" + else + dns_information="${dns_count} servers" + fi + + + # DNSSEC + DNSSEC="$(echo "${config}" | jq .config.dnsmasq.dnssec)" + if [ "${DNSSEC}" = "true" ]; then + dnssec_status="Enabled" + dnssec_heatmap=${green_text} + else + dnssec_status="Disabled" + dnssec_heatmap=${red_text} + fi + + # Conditional forwarding + CONDITIONAL_FORWARDING="$(echo "${config}" | jq .config.dnsmasq.rev_server.active)" + if [ "${CONDITIONAL_FORWARDING}" = "true" ]; then + conditional_forwarding_status="Enabled" + conditional_forwarding_heatmap=${green_text} + else + conditional_forwarding_status="Disabled" + conditional_forwarding_heatmap=${red_text} + fi + + # Default interface data + iface_name="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .name')" + tx_bytes="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .tx.num')" + tx_bytes_unit="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .tx.unit')" tx_bytes=$(printf "%.1f %b" "${tx_bytes}" "${tx_bytes_unit}") - rx_bytes="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].rx.num)" - rx_bytes_unit="$(echo "${interfaces_raw}" | jq --raw-output .interfaces[0].rx.unit)" + rx_bytes="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .rx.num')" + rx_bytes_unit="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .rx.unit')" rx_bytes=$(printf "%.1f %b" "${rx_bytes}" "${rx_bytes_unit}") } GetPiholeInformation() { - # Get FTL status + sysinfo=$(GetFTLData "/ftl/sysinfo") - # Get FTL's current PID - ftlPID="$(getFTLPID)" + # Get FTL's current PID + ftlPID="$(echo "${sysinfo}" | jq .ftl.pid)" - # If FTL is not running (getFTLPID returns -1), set all variables to "not running" + # If FTL is not running (ftlPID is -1), set all variables to "not running" ftl_down_flag=false if [ "${ftlPID}" = "-1" ]; then ftl_status="Not running" @@ -503,8 +471,10 @@ GetPiholeInformation() { ftl_heatmap=${green_text} ftl_check_box=${check_box_good} # Get FTL CPU and memory usage - ftl_cpu="$(ps -p "${ftlPID}" -o %cpu | tail -n1 | tr -d '[:space:]')" - ftl_mem_percentage="$(ps -p "${ftlPID}" -o %mem | tail -n1 | tr -d '[:space:]')" + ftl_cpu_raw="$(echo "${sysinfo}" | jq '.ftl."%cpu"')" + ftl_mem_percentage_raw="$(echo "${sysinfo}" | jq '.ftl."%mem"')" + ftl_cpu="$(printf "%.1f" "${ftl_cpu_raw}")%" + ftl_mem_percentage="$(printf "%.1f" "${ftl_mem_percentage_raw}")%" # Get Pi-hole (blocking) status ftl_dns_port=$(GetFTLData "/dns/port" | jq .dns_port) fi @@ -531,133 +501,133 @@ GetVersionInformation() { out_of_date_flag=false versions_raw=$(GetFTLData "/version") - # Check if core version - CORE_BRANCH="$(echo "${versions_raw}" | jq --raw-output .core.branch)" - CORE_VERSION=$(echo "${versions_raw}" | jq --raw-output .core.tag | tr -d '[:alpha:]' | awk -F '-' '{printf $1}') - GITHUB_CORE_VERSION=$(pihole -v -p | awk '{print $(NF)}' | tr -d ')') - CORE_HASH - GITHUB_CORE_HASH + # Gather core version information... + CORE_BRANCH="$(echo "${versions_raw}" | jq --raw-output .version.core.local.branch)" + CORE_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.core.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_CORE_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.core.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + CORE_HASH="$(echo "${versions_raw}" | jq --raw-output .version.core.local.hash)" + GITHUB_CORE_HASH="$(echo "${versions_raw}" | jq --raw-output .version.core.remote.hash)" - # Gather core version information... - # Extract vx.xx or vx.xx.xxx version - CORE_VERSION="$(echo "${CORE_VERSION}" | grep -oE '^v[0-9]+([.][0-9]+){1,2}')" - if [ "${CORE_BRANCH}" = "master" ]; then - core_version_converted="$(VersionConverter "${CORE_VERSION}")" - core_version_latest_converted=$(VersionConverter "${GITHUB_CORE_VERSION}") + if [ "${CORE_BRANCH}" = "master" ]; then + core_version_converted="$(VersionConverter "${CORE_VERSION}")" + core_version_latest_converted=$(VersionConverter "${GITHUB_CORE_VERSION}") - if [ "${core_version_converted}" -lt "${core_version_latest_converted}" ]; then - out_of_date_flag="true" - core_version_heatmap=${red_text} + if [ "${core_version_converted}" -lt "${core_version_latest_converted}" ]; then + out_of_date_flag="true" + core_version_heatmap=${red_text} + else + core_version_heatmap=${green_text} + fi else - core_version_heatmap=${green_text} + # Custom branch + if [ -z "${CORE_BRANCH}" ]; then + # Branch name is empty, something went wrong + core_version_heatmap=${red_text} + CORE_VERSION="?" + else + if [ "${CORE_HASH}" = "${GITHUB_CORE_HASH}" ]; then + # up-to-date + core_version_heatmap=${green_text} + else + # out-of-date + out_of_date_flag="true" + core_version_heatmap=${red_text} + fi + # shorten common branch names (fix/, tweak/, new/) + # use the first 7 characters of the branch name as version + CORE_VERSION="$(printf '%s' "$CORE_BRANCH" | sed 's/fix\//f\//;s/new\//n\//;s/tweak\//t\//' | cut -c 1-7)" + fi fi - else - # Custom branch - if [ -z "${CORE_BRANCH}" ]; then - # Branch name is empty, something went wrong - core_version_heatmap=${red_text} - CORE_VERSION="?" - else - if [ "${CORE_HASH}" = "${GITHUB_CORE_HASH}" ]; then - # up-to-date - core_version_heatmap=${green_text} - else - # out-of-date - out_of_date_flag="true" - core_version_heatmap=${red_text} - fi - # shorten common branch names (fix/, tweak/, new/) - # use the first 7 characters of the branch name as version - CORE_VERSION="$(printf '%s' "$CORE_BRANCH" | sed 's/fix\//f\//;s/new\//n\//;s/tweak\//t\//' | cut -c 1-7)" - fi - fi - # Gather web version information... - # Extract vx.xx or vx.xx.xxx version - if [ "$INSTALL_WEB_INTERFACE" = true ]; then - WEB_BRANCH="$(echo "${versions_raw}" | jq --raw-output .web.branch)" - WEB_VERSION=$(echo "${versions_raw}" | jq --raw-output .web.tag | tr -d '[:alpha:]' | awk -F '-' '{printf $1}') - GITHUB_WEB_VERSION - WEB_HASH - GITHUB_WEB_HASH + WEB_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.web.local.version)" - if [ "${WEB_BRANCH}" = "master" ]; then - web_version_converted="$(VersionConverter "${WEB_VERSION}")" - web_version_latest_converted=$(VersionConverter "${GITHUB_WEB_VERSION}") + if [ ! "$WEB_VERSION" = "null" ]; then + WEB_BRANCH="$(echo "${versions_raw}" | jq --raw-output .version.web.local.branch)" + WEB_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.web.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_WEB_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.web.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + WEB_HASH="$(echo "${versions_raw}" | jq --raw-output .version.web.local.hash)" + GITHUB_WEB_HASH="$(echo "${versions_raw}" | jq --raw-output .version.web.remote.hash)" - if [ "${web_version_converted}" -lt "${web_version_latest_converted}" ]; then - out_of_date_flag="true" - web_version_heatmap=${red_text} - else - web_version_heatmap=${green_text} - fi + if [ "${WEB_BRANCH}" = "master" ]; then + web_version_converted="$(VersionConverter "${WEB_VERSION}")" + web_version_latest_converted=$(VersionConverter "${GITHUB_WEB_VERSION}") + + if [ "${web_version_converted}" -lt "${web_version_latest_converted}" ]; then + out_of_date_flag="true" + web_version_heatmap=${red_text} + else + web_version_heatmap=${green_text} + fi - else - # Custom branch - if [ -z "${WEB_BRANCH}" ]; then - # Branch name is empty, something went wrong - web_version_heatmap=${red_text} - WEB_VERSION="?" - else - if [ "${WEB_HASH}" = "${GITHUB_WEB_HASH}" ]; then - # up-to-date - web_version_heatmap=${green_text} else - # out-of-date - out_of_date_flag="true" - web_version_heatmap=${red_text} + # Custom branch + if [ -z "${WEB_BRANCH}" ]; then + # Branch name is empty, something went wrong + web_version_heatmap=${red_text} + WEB_VERSION="?" + else + if [ "${WEB_HASH}" = "${GITHUB_WEB_HASH}" ]; then + # up-to-date + web_version_heatmap=${green_text} + else + # out-of-date + out_of_date_flag="true" + web_version_heatmap=${red_text} + fi + # shorten common branch names (fix/, tweak/, new/) + # use the first 7 characters of the branch name as version + WEB_VERSION="$(printf '%s' "$WEB_BRANCH" | sed 's/fix\//f\//;s/new\//n\//;s/tweak\//t\//' | cut -c 1-7)" + fi fi - # shorten common branch names (fix/, tweak/, new/) - # use the first 7 characters of the branch name as version - WEB_VERSION="$(printf '%s' "$WEB_BRANCH" | sed 's/fix\//f\//;s/new\//n\//;s/tweak\//t\//' | cut -c 1-7)" - fi - fi - else - # Web interface not installed - WEB_VERSION="N/A" - web_version_heatmap=${yellow_text} - fi - - # Gather FTL version information... - # Extract vx.xx or vx.xx.xxx version - FTL_BRANCH="$(echo "${versions_raw}" | jq --raw-output .ftl.branch)" - FTL_VERSION=$(echo "${versions_raw}" | jq --raw-output .ftl.tag | tr -d '[:alpha:]' | awk -F '-' '{printf $1}') - GITHUB_FTL_VERSION - FTL_HASH - GITHUB_FTL_HASH - - - if [ "${FTL_BRANCH}" = "master" ]; then - ftl_version_converted="$(VersionConverter "${FTL_VERSION}")" - ftl_version_latest_converted=$(VersionConverter "${GITHUB_FTL_VERSION}") - - if [ "${ftl_version_converted}" -lt "${ftl_version_latest_converted}" ]; then - out_of_date_flag="true" - ftl_version_heatmap=${red_text} else - ftl_version_heatmap=${green_text} + # Web interface not installed + WEB_VERSION="N/A" + web_version_heatmap=${yellow_text} fi - else - # Custom branch - if [ -z "${FTL_BRANCH}" ]; then - # Branch name is empty, something went wrong - ftl_version_heatmap=${red_text} - FTL_VERSION="?" + + # Gather FTL version information... + FTL_BRANCH="$(echo "${versions_raw}" | jq --raw-output .version.ftl.local.branch)" + FTL_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.ftl.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_FTL_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.ftl.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + FTL_HASH="$(echo "${versions_raw}" | jq --raw-output .version.ftl.local.hash)" + GITHUB_FTL_HASH="$(echo "${versions_raw}" | jq --raw-output .version.ftl.remote.hash)" + + + if [ "${FTL_BRANCH}" = "master" ]; then + ftl_version_converted="$(VersionConverter "${FTL_VERSION}")" + ftl_version_latest_converted=$(VersionConverter "${GITHUB_FTL_VERSION}") + + if [ "${ftl_version_converted}" -lt "${ftl_version_latest_converted}" ]; then + out_of_date_flag="true" + ftl_version_heatmap=${red_text} + else + ftl_version_heatmap=${green_text} + fi else - if [ "${FTL_HASH}" = "${GITHUB_FTL_HASH}" ]; then - # up-to-date - ftl_version_heatmap=${green_text} - else - # out-of-date - out_of_date_flag="true" - ftl_version_heatmap=${red_text} - fi - # shorten common branch names (fix/, tweak/, new/) - # use the first 7 characters of the branch name as version - FTL_VERSION="$(printf '%s' "$FTL_BRANCH" | sed 's/fix\//f\//;s/new\//n\//;s/tweak\//t\//' | cut -c 1-7)" + # Custom branch + if [ -z "${FTL_BRANCH}" ]; then + # Branch name is empty, something went wrong + ftl_version_heatmap=${red_text} + FTL_VERSION="?" + else + if [ "${FTL_HASH}" = "${GITHUB_FTL_HASH}" ]; then + # up-to-date + ftl_version_heatmap=${green_text} + else + # out-of-date + out_of_date_flag="true" + ftl_version_heatmap=${red_text} + fi + # shorten common branch names (fix/, tweak/, new/) + # use the first 7 characters of the branch name as version + FTL_VERSION="$(printf '%s' "$FTL_BRANCH" | sed 's/fix\//f\//;s/new\//n\//;s/tweak\//t\//' | cut -c 1-7)" + fi fi - fi + + # Gather DOCKER version information... + # returns "null" if not running Pi-hole in Docker container + DOCKER_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.docker.local)" } @@ -725,9 +695,9 @@ GenerateSizeDependendOutput() { # System uptime if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then - system_uptime=$(echo "${system_uptime_raw}" | awk -F'( |,|:)+' '{if ($7=="min") m=$6; else {if ($7~/^day/){if ($9=="min") {d=$6;m=$8} else {d=$6;h=$8;m=$9}} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours"}') + system_uptime="$(convertUptime "${system_uptime_raw}" | awk -F ',' '{print $1 "," $2}')" else - system_uptime=$(echo "${system_uptime_raw}" | awk -F'( |,|:)+' '{if ($7=="min") m=$6; else {if ($7~/^day/){if ($9=="min") {d=$6;m=$8} else {d=$6;h=$8;m=$9}} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes"}') + system_uptime="$(convertUptime "${system_uptime_raw}")" fi # Bar generations @@ -759,10 +729,10 @@ SetStatusMessage() { if [ "${hot_flag}" = true ]; then # Check if CPU temperature is high pico_status="${pico_status_hot}" - mini_status="${mini_status_hot} ${blinking_text}${red_text}${cpu_temp}${reset_text}" - tiny_status="${tiny_status_hot} ${blinking_text}${red_text}${cpu_temp}${reset_text}" - full_status="${full_status_hot} ${blinking_text}${red_text}${cpu_temp}${reset_text}" - mega_status="${mega_status_hot} ${blinking_text}${red_text}${cpu_temp}${reset_text}" + mini_status="${mini_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" + tiny_status="${tiny_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" + full_status="${full_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" + mega_status="${mega_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" elif [ "${ftl_down_flag}" = true ]; then # Check if FTL is down @@ -937,7 +907,7 @@ PrintDashboard() { fi moveXOffset; printf "%s${clear_line}\n" "${bold_text}SYSTEM ==============================================${reset_text}" moveXOffset; printf " %-10s%-29s${clear_line}\n" "Uptime:" "${system_uptime}" - moveXOffset; printf " %-10s${temp_heatmap}%-17s${reset_text} %-8s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-4s${reset_text}${clear_line}\n" "CPU Temp:" "${cpu_temp}" "Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" + moveXOffset; printf " %-10s${temp_heatmap}%-17s${reset_text} %-8s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-4s${reset_text}${clear_line}\n" "CPU Temp:" "${temperature}" "Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" moveXOffset; printf " %-10s[${memory_heatmap}%-7s${reset_text}] %-6s %-8s[${cpu_load_1_heatmap}%-7s${reset_text}] %-5s${clear_line}" "Memory:" "${memory_bar}" "${memory_percent}%" "CPU:" "${cpu_bar}" "${cpu_percent}%" elif [ "$1" = "regular" ] || [ "$1" = "slim" ]; then # slim is a screen with at least 60 columns and exactly 21 lines @@ -974,7 +944,7 @@ PrintDashboard() { fi moveXOffset; printf "%s${clear_line}\n" "${bold_text}SYSTEM =====================================================${reset_text}" moveXOffset; printf " %-10s%-39s${clear_line}\n" "Uptime:" "${system_uptime}" - moveXOffset; printf " %-10s${temp_heatmap}%-21s${reset_text}%-10s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-4s${reset_text}${clear_line}\n" "CPU Temp:" "${cpu_temp}" "CPU Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" + moveXOffset; printf " %-10s${temp_heatmap}%-21s${reset_text}%-10s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-4s${reset_text}${clear_line}\n" "CPU Temp:" "${temperature}" "CPU Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" moveXOffset; printf " %-10s[${memory_heatmap}%-10s${reset_text}] %-6s %-10s[${cpu_load_1_heatmap}%-10s${reset_text}] %-5s${clear_line}" "Memory:" "${memory_bar}" "${memory_percent}%" "CPU Load:" "${cpu_bar}" "${cpu_percent}%" else # ${padd_size} = mega # mega is a screen with at least 80 columns and 26 lines @@ -1003,7 +973,7 @@ PrintDashboard() { moveXOffset; printf "%s${clear_line}\n" "${bold_text}SYSTEM =========================================================================${reset_text}" moveXOffset; printf " %-10s%-39s${clear_line}\n" "Device:" "${sys_model}" moveXOffset; printf " %-10s%-39s %-10s[${memory_heatmap}%-10s${reset_text}] %-6s${clear_line}\n" "Uptime:" "${system_uptime}" "Memory:" "${memory_bar}" "${memory_percent}%" - moveXOffset; printf " %-10s${temp_heatmap}%-10s${reset_text} %-10s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-7s${reset_text} %-10s[${memory_heatmap}%-10s${reset_text}] %-6s${clear_line}" "CPU Temp:" "${cpu_temp}" "CPU Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" "CPU Load:" "${cpu_bar}" "${cpu_percent}%" + moveXOffset; printf " %-10s${temp_heatmap}%-10s${reset_text} %-10s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-7s${reset_text} %-10s[${memory_heatmap}%-10s${reset_text}] %-6s${clear_line}" "CPU Temp:" "${temperature}" "CPU Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" "CPU Load:" "${cpu_bar}" "${cpu_percent}%" fi # Clear to end of screen (below the drawn dashboard) @@ -1212,7 +1182,12 @@ truncateString() { fi } - +# Converts seconds to days, hours, minuts +#https://unix.stackexchange.com/a/338844 +convertUptime() { + # shellcheck disable=SC2016 + eval "echo $(date -ud "@$1" +'$((%s/3600/24)) days, %H hours, %M minutes')" +} ########################################## MAIN FUNCTIONS ########################################## @@ -1229,7 +1204,7 @@ OutputJSON() { # Test if the authentication endpoint is availabe TestAPIAvailability # Authenticate with the FTL server - printf "%b" "Establishing connection with FTL...\n" + moveXOffset; printf "%b" "Establishing connection with FTL...\n" Authenthication GetSummaryInformation @@ -1254,7 +1229,7 @@ StartupRoutine(){ moveXOffset; printf "%b" "START-UP ===========\n" # Authenticate with the FTL server - printf "%b" "Establishing connection with FTL...\n" + moveXOffset; printf "%b" "Establishing connection with FTL...\n" Authenthication printf "%b" "Starting PADD...\n" @@ -1267,7 +1242,7 @@ StartupRoutine(){ # Get our information for the first time moveXOffset; printf "%b" " [■■■■······] 40%\r" - GetSystemInformation + GetVersionInformation moveXOffset; printf "%b" " [■■■■■·····] 50%\r" GetSummaryInformation moveXOffset; printf "%b" " [■■■■■■····] 60%\r" @@ -1275,7 +1250,7 @@ StartupRoutine(){ moveXOffset; printf "%b" " [■■■■■■■···] 70%\r" GetNetworkInformation moveXOffset; printf "%b" " [■■■■■■■■··] 80%\r" - GetVersionInformation + GetSystemInformation moveXOffset; printf "%b" " [■■■■■■■■■·] 90%\r" GetPADDInformation moveXOffset; printf "%b" " [■■■■■■■■■■] 100%\n" @@ -1284,10 +1259,12 @@ StartupRoutine(){ moveXOffset; PrintLogo "$1" moveXOffset; echo "START UP =====================" # Authenticate with the FTL server - printf "%b" "Establishing connection with FTL...\n" + moveXOffset; printf "%b" "Establishing connection with FTL...\n" Authenthication # Get our information for the first time + moveXOffset; echo "- Gathering version info." + GetVersionInformation moveXOffset; echo "- Gathering system info." GetSystemInformation moveXOffset; echo "- Gathering Pi-hole info." @@ -1295,8 +1272,6 @@ StartupRoutine(){ GetSummaryInformation moveXOffset; echo "- Gathering network info." GetNetworkInformation - moveXOffset; echo "- Gathering version info." - GetVersionInformation GetPADDInformation moveXOffset; echo " - Core $CORE_VERSION, Web $WEB_VERSION" moveXOffset; echo " - FTL $FTL_VERSION, PADD $padd_version" @@ -1314,11 +1289,13 @@ StartupRoutine(){ # Authenticate with the FTL server - printf "%b" "Establishing connection with FTL...\n" + moveXOffset; printf "%b" "Establishing connection with FTL...\n" Authenthication # Get our information for the first time + moveXOffset; echo "- Gathering version information..." + GetVersionInformation moveXOffset; echo "- Gathering system information..." GetSystemInformation moveXOffset; echo "- Gathering Pi-hole information..." @@ -1326,8 +1303,7 @@ StartupRoutine(){ GetPiholeInformation moveXOffset; echo "- Gathering network information..." GetNetworkInformation - moveXOffset; echo "- Gathering version information..." - GetVersionInformation + GetPADDInformation moveXOffset; echo " - Pi-hole Core $CORE_VERSION" moveXOffset; echo " - Web Admin $WEB_VERSION" From 1a23a9c3d8eca1eabd24a25c9d2d186975165693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 16 Jan 2023 21:12:04 +0100 Subject: [PATCH 16/96] Mask user password during input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 57 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/padd.sh b/padd.sh index 0245cb0..6b8e7dc 100755 --- a/padd.sh +++ b/padd.sh @@ -144,14 +144,8 @@ Authenthication() { moveXOffset; echo "Wrong password supplied, please enter the correct password:" fi - # POSIX's `read` does not support `-s` option (suppressing the input) - # this workaround changes the terminal characteristics to not echo input and later rests this option - # credits https://stackoverflow.com/a/4316765 - - stty -echo - read -r password - stty "${stty_orig}" - echo "" + # secretly read the password + moveXOffset; secretRead; printf '\n' # Try to authenticate again ChallengeResponse @@ -1189,6 +1183,53 @@ convertUptime() { eval "echo $(date -ud "@$1" +'$((%s/3600/24)) days, %H hours, %M minutes')" } +secretRead() { + + # POSIX compliant function to read user-input and + # mask every character entered by (*) + # + # This is challenging, because in POSIX, `read` does not support + # `-s` option (suppressing the input) or + # `-n` option (reading n chars) + + + # This workaround changes the terminal characteristics to not echo input and later rests this option + # credits https://stackoverflow.com/a/4316765 + # showing astrix instead of password + # https://stackoverflow.com/a/24600839 + # https://unix.stackexchange.com/a/464963 + + stty -echo # do not echo user input + stty -icanon min 1 time 0 # disable cannonical mode https://man7.org/linux/man-pages/man3/termios.3.html + + unset password + unset key + unset charcount + charcount=0 + while key=$(dd ibs=1 count=1 2>/dev/null); do #read one byte of input + if [ "${key}" = "$(printf '\0' | tr -d '\0')" ] ; then + # Enter - accept password + break + fi + if [ "${key}" = "$(printf '\177')" ] ; then + # Backspace + if [ $charcount -gt 0 ] ; then + charcount=$((charcount-1)) + printf '\b \b' + password="${password%?}" + fi + else + # any other character + charcount=$((charcount+1)) + printf '*' + password="$password$key" + fi + done + + # restore original terminal settings + stty "${stty_orig}" +} + ########################################## MAIN FUNCTIONS ########################################## OutputJSON() { From d3a209e40718c0ea8f518b72bb96607f036a39f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 16 Jan 2023 21:25:39 +0100 Subject: [PATCH 17/96] Format memory_percentage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/padd.sh b/padd.sh index 6b8e7dc..a1add84 100755 --- a/padd.sh +++ b/padd.sh @@ -299,7 +299,8 @@ GetSystemInformation() { cpu_percent=$(printf %.1f "$(echo "${sysinfo}" | jq .system.cpu.load.percent[0])") # Memory use, heatmap and bar - memory_percent="$(echo "${sysinfo}" | jq '.system.memory.ram."%used"')" + memory_percent_raw="$(echo "${sysinfo}" | jq '.system.memory.ram."%used"')" + memory_percent=$(printf %.1f "${memory_percent_raw}") memory_heatmap="$(HeatmapGenerator "${memory_percent}")" # Get device model From e0f78cfaf0793f5613ed8663900a84e1230aa7ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 19 Jan 2023 21:40:14 +0100 Subject: [PATCH 18/96] Adjust for changed API endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/padd.sh b/padd.sh index a1add84..8bae11c 100755 --- a/padd.sh +++ b/padd.sh @@ -471,7 +471,7 @@ GetPiholeInformation() { ftl_cpu="$(printf "%.1f" "${ftl_cpu_raw}")%" ftl_mem_percentage="$(printf "%.1f" "${ftl_mem_percentage_raw}")%" # Get Pi-hole (blocking) status - ftl_dns_port=$(GetFTLData "/dns/port" | jq .dns_port) + ftl_dns_port=$(GetFTLData "/config" | jq .config.dnsmasq.port) fi From 7c6efb10bcec045ee5a1b75e2dbc09f12ff67486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 20 Jan 2023 07:29:49 +0100 Subject: [PATCH 19/96] Use 127.0.0.1 instead of pi.hole as default address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/padd.sh b/padd.sh index 991a85e..f13e184 100755 --- a/padd.sh +++ b/padd.sh @@ -103,7 +103,7 @@ padd_logo_retro_3="${bold_text}${green_text}| ${red_text}/${yellow_text}-${gre ConstructAPI() { # If no arguments were supplied set them to default if [ -z "${URL}" ]; then - URL=pi.hole + URL=127.0.0.1 fi if [ -z "${PORT}" ]; then PORT=8080 @@ -1475,7 +1475,7 @@ DisplayHelp() { ::: -xoff [num] set the x-offset, reference is the upper left corner, disables auto-centering ::: -yoff [num] set the y-offset, reference is the upper left corner, disables auto-centering ::: -::: -u URL or address of your Pi-hole (default: pi.hole) +::: -u URL or address of your Pi-hole (default: 127.0.0.1) ::: -p Port of your Pi-hole's API (default: 8080) ::: -a Path where your Pi-hole's API is hosted (default: api) ::: -s Your Pi-hole's password, required to access the API From 9acad77431fdf8fb73a596aa7fad391a1f28dfce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sun, 22 Jan 2023 09:51:02 +0100 Subject: [PATCH 20/96] Adjust FTL endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/padd.sh b/padd.sh index f13e184..9976936 100755 --- a/padd.sh +++ b/padd.sh @@ -207,14 +207,14 @@ GetFTLData() { GetSummaryInformation() { summary=$(GetFTLData "/stats/summary") cache_info=$(GetFTLData "/dns/cache") - sysinfo=$(GetFTLData "/ftl/sysinfo") + ftl_info=$(GetFTLData "/info/ftl") dns_blocking=$(GetFTLData "/dns/blocking") - clients=$(echo "${sysinfo}" | jq .ftl.clients.active ) + clients=$(echo "${ftl_info}" | jq .ftl.clients.active ) blocking_enabled=$(echo "${dns_blocking}" | jq .blocking ) - domains_being_blocked_raw=$(echo "${sysinfo}" | jq .ftl.database.gravity) + domains_being_blocked_raw=$(echo "${ftl_info}" | jq .ftl.database.gravity) domains_being_blocked=$(printf "%.f" "${domains_being_blocked_raw}") dns_queries_today_raw=$(echo "$summary" | jq .queries.total ) @@ -244,15 +244,15 @@ GetSummaryInformation() { } GetSystemInformation() { - sysinfo=$(GetFTLData "/ftl/sysinfo") + sysinfo=$(GetFTLData "/info/system") # System uptime system_uptime_raw=$(echo "${sysinfo}" | jq .system.uptime ) # CPU temperature and unit - cpu_temp_raw=$(echo "${sysinfo}" | jq .system.sensors[0].value) + cpu_temp_raw=$(GetFTLData "/info/sensors" | jq .sensors[0].value) cpu_temp=$(printf "%.1f" "${cpu_temp_raw}") - temp_unit=$(echo "${sysinfo}" | jq --raw-output .system.sensors[0].unit) + temp_unit=$(GetFTLData "/info/sensors" | jq --raw-output .sensors[0].unit) # Temp + Unit if [ "${temp_unit}" = "C" ]; then @@ -301,7 +301,7 @@ GetSystemInformation() { memory_heatmap="$(HeatmapGenerator "${memory_percent}")" # Get device model - sys_model="$(echo "${sysinfo}" | jq --raw-output .system.model)" + sys_model="$(GetFTLData "/info/host" | jq --raw-output .host.model)" # DOCKER_VERSION is set during GetVersionInformation, so this needs to run first during startup if [ ! "${DOCKER_VERSION}" = "null" ]; then @@ -319,7 +319,6 @@ GetSystemInformation() { GetNetworkInformation() { interfaces_raw=$(GetFTLData "/network/interfaces") - sysinfo=$(GetFTLData "/ftl/sysinfo") config=$(GetFTLData "/config") # Get pi IPv4 address of the default interface @@ -387,7 +386,7 @@ GetNetworkInformation() { fi # Get hostname - pi_hostname="$(echo "${sysinfo}" | jq --raw-output .system.uname.nodename)" + pi_hostname="$(GetFTLData "/info/host" | jq --raw-output .host.uname.nodename)" full_hostname=${pi_hostname} # when PI-hole is the DHCP server, append the domain to the hostname if [ "${DHCP_ACTIVE}" = "true" ]; then @@ -443,7 +442,7 @@ GetNetworkInformation() { } GetPiholeInformation() { - sysinfo=$(GetFTLData "/ftl/sysinfo") + sysinfo=$(GetFTLData "/info/ftl") # Get FTL's current PID ftlPID="$(echo "${sysinfo}" | jq .ftl.pid)" @@ -491,7 +490,7 @@ fi GetVersionInformation() { out_of_date_flag=false - versions_raw=$(GetFTLData "/version") + versions_raw=$(GetFTLData "/info/version") # Gather DOCKER version information... # returns "null" if not running Pi-hole in Docker container @@ -1297,6 +1296,9 @@ StartupRoutine(){ moveXOffset; PrintLogo "$1" moveXOffset; printf "%b" "START-UP ===========\n" + # Test if the authentication endpoint is availabe + TestAPIAvailability + # Authenticate with the FTL server moveXOffset; printf "%b" "Establishing connection with FTL...\n" Authenthication @@ -1327,6 +1329,8 @@ StartupRoutine(){ elif [ "$1" = "mini" ]; then moveXOffset; PrintLogo "$1" moveXOffset; echo "START UP =====================" + # Test if the authentication endpoint is availabe + TestAPIAvailability # Authenticate with the FTL server moveXOffset; printf "%b" "Establishing connection with FTL...\n" Authenthication @@ -1359,6 +1363,8 @@ StartupRoutine(){ moveXOffset; echo "START UP ===================================================" fi + # Test if the authentication endpoint is availabe + TestAPIAvailability # Authenticate with the FTL server moveXOffset; printf "%b" "Establishing connection with FTL...\n" @@ -1557,13 +1563,9 @@ main(){ # Save current terminal settings (needed for later restore after password prompt) stty_orig=$(stty -g) - # Construct FTL's API address depending on the arguments supplied ConstructAPI - # Test if the authentication endpoint is availabe - TestAPIAvailability - SizeChecker StartupRoutine ${padd_size} From 9eb478a35f31f10cf22ffc5409529936c9e08b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sun, 22 Jan 2023 21:17:01 +0100 Subject: [PATCH 21/96] Handle connection loss and re-authentication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 203 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 116 insertions(+), 87 deletions(-) diff --git a/padd.sh b/padd.sh index 9976936..f974e54 100755 --- a/padd.sh +++ b/padd.sh @@ -52,7 +52,7 @@ pico_status_ok="${check_box_good} Sys. OK" pico_status_update="${check_box_info} Update" pico_status_hot="${check_box_bad} Sys. Hot!" pico_status_off="${check_box_info} No blck" -pico_status_ftl_down="${check_box_bad} FTL Down" +pico_status_ftl_down="${check_box_bad} No CXN" pico_status_dns_down="${check_box_bad} DNS Down" # MINI STATUS @@ -60,7 +60,7 @@ mini_status_ok="${check_box_good} System OK" mini_status_update="${check_box_info} Update avail." mini_status_hot="${check_box_bad} System is hot!" mini_status_off="${check_box_info} No blocking!" -mini_status_ftl_down="${check_box_bad} FTL down!" +mini_status_ftl_down="${check_box_bad} No connection!" mini_status_dns_down="${check_box_bad} DNS off!" # REGULAR STATUS @@ -68,7 +68,7 @@ full_status_ok="${check_box_good} System is healthy" full_status_update="${check_box_info} Updates are available" full_status_hot="${check_box_bad} System is hot!" full_status_off="${check_box_info} Blocking is disabled" -full_status_ftl_down="${check_box_bad} FTL is down!" +full_status_ftl_down="${check_box_bad} No connection!" full_status_dns_down="${check_box_bad} DNS is off!" # MEGA STATUS @@ -76,7 +76,7 @@ mega_status_ok="${check_box_good} Your system is healthy" mega_status_update="${check_box_info} Updates are available" mega_status_hot="${check_box_bad} Your system is hot!" mega_status_off="${check_box_info} Blocking is disabled!" -mega_status_ftl_down="${check_box_bad} FTLDNS service is not running!" +mega_status_ftl_down="${check_box_bad} No connection to FTL!" mega_status_dns_down="${check_box_bad} Pi-hole's DNS server is off!" # TINY STATUS @@ -84,7 +84,7 @@ tiny_status_ok="${check_box_good} System is healthy" tiny_status_update="${check_box_info} Updates are available" tiny_status_hot="${check_box_bad} System is hot!" tiny_status_off="${check_box_info} Blocking is disabled" -tiny_status_ftl_down="${check_box_bad} FTL is down!" +tiny_status_ftl_down="${check_box_bad} No connection to FTL!" tiny_status_dns_down="${check_box_bad} DNS is off!" # Text only "logos" @@ -172,6 +172,7 @@ DeleteSession() { ChallengeResponse() { # Challenge-response authentication + local response # Compute password hash from user password # Compute password hash twice to avoid rainbow table vulnerability @@ -182,7 +183,7 @@ ChallengeResponse() { # Get challenge from FTL # Calculate response based on challenge and password hash # Send response & get session response - challenge="$(curl --silent -X GET "http://${URL}:${PORT}/${APIPATH}/auth" | jq --raw-output .challenge)" + challenge="$(curl --silent -X GET "http://${URL}:${PORT}/${APIPATH}/auth" | jq --raw-output .challenge 2>/dev/null)" response="$(printf "%b" "${challenge}:${pwhash}" | sha256sum | sed 's/\s.*$//')" sessionResponse="$(curl --silent -X POST "http://${URL}:${PORT}/${APIPATH}/auth" --data "{\"response\":\"${response}\"}" )" @@ -192,13 +193,29 @@ ChallengeResponse() { exit 1 fi # obtain validity and session ID from session response - validSession=$(echo "${sessionResponse}"| jq .session.valid) - SID=$(echo "${sessionResponse}"| jq --raw-output .session.sid) + validSession=$(echo "${sessionResponse}"| jq .session.valid 2>/dev/null) + SID=$(echo "${sessionResponse}"| jq --raw-output .session.sid 2>/dev/null) } GetFTLData() { - data=$(curl -sS -X GET "http://${URL}:${PORT}/${APIPATH}$1" -H "Accept: application/json" -H "sid: ${SID}" ) - echo "${data}" + local response + # get the data from querying the API as well as the http status code + response=$(curl -s -w "%{http_code}" -X GET "http://${URL}:${PORT}/${APIPATH}$1" -H "Accept: application/json" -H "sid: ${SID}" ) + + # status are the last 3 characters + status=$(printf %s "${response#"${response%???}"}") + # data is everything from repsonse without the last 3 characters + data=$(printf %s "${response%???}") + + if [ "${status}" = 200 ]; then + echo "${data}" + elif [ "${status}" = 000 ]; then + # connection lost + echo "000" + elif [ "${status}" = 401 ]; then + # unauthorized + echo "401" + fi } @@ -210,36 +227,36 @@ GetSummaryInformation() { ftl_info=$(GetFTLData "/info/ftl") dns_blocking=$(GetFTLData "/dns/blocking") - clients=$(echo "${ftl_info}" | jq .ftl.clients.active ) + clients=$(echo "${ftl_info}" | jq .ftl.clients.active 2>/dev/null) - blocking_enabled=$(echo "${dns_blocking}" | jq .blocking ) + blocking_enabled=$(echo "${dns_blocking}" | jq .blocking 2>/dev/null) - domains_being_blocked_raw=$(echo "${ftl_info}" | jq .ftl.database.gravity) + domains_being_blocked_raw=$(echo "${ftl_info}" | jq .ftl.database.gravity 2>/dev/null) domains_being_blocked=$(printf "%.f" "${domains_being_blocked_raw}") - dns_queries_today_raw=$(echo "$summary" | jq .queries.total ) + dns_queries_today_raw=$(echo "$summary" | jq .queries.total 2>/dev/null) dns_queries_today=$(printf "%.f" "${dns_queries_today_raw}") - ads_blocked_today_raw=$(echo "$summary" | jq .queries.blocked ) + ads_blocked_today_raw=$(echo "$summary" | jq .queries.blocked 2>/dev/null) ads_blocked_today=$(printf "%.f" "${ads_blocked_today_raw}") - ads_percentage_today_raw=$(echo "$summary" | jq .queries.percent_blocked) + ads_percentage_today_raw=$(echo "$summary" | jq .queries.percent_blocked 2>/dev/null) ads_percentage_today=$(printf "%.1f" "${ads_percentage_today_raw}") - cache_size=$(echo "$cache_info" | jq .cache.size) - cache_evictions=$(echo "$cache_info" | jq .cache.evicted) - cache_inserts=$(echo "$cache_info"| jq .cache.inserted) + cache_size=$(echo "$cache_info" | jq .cache.size 2>/dev/null) + cache_evictions=$(echo "$cache_info" | jq .cache.evicted 2>/dev/null) + cache_inserts=$(echo "$cache_info"| jq .cache.inserted 2>/dev/null) - latest_blocked_raw=$(GetFTLData "/stats/recent_blocked?show=1" | jq --raw-output .blocked[0]) + latest_blocked_raw=$(GetFTLData "/stats/recent_blocked?show=1" | jq --raw-output .blocked[0] 2>/dev/null) - top_blocked_raw=$(GetFTLData "/stats/top_domains?blocked=true" | jq --raw-output .domains[0].domain) + top_blocked_raw=$(GetFTLData "/stats/top_domains?blocked=true" | jq --raw-output .domains[0].domain 2>/dev/null) - top_domain_raw=$(GetFTLData "/stats/top_domains" | jq --raw-output .domains[0].domain) + top_domain_raw=$(GetFTLData "/stats/top_domains" | jq --raw-output .domains[0].domain 2>/dev/null) - top_client_raw=$(GetFTLData "/stats/top_clients" | jq --raw-output .clients[0].name) + top_client_raw=$(GetFTLData "/stats/top_clients" | jq --raw-output .clients[0].name 2>/dev/null) if [ -z "${top_client_raw}" ]; then # if no hostname was supplied, use IP - top_client_raw=$(GetFTLData "/stats/top_clients" | jq --raw-output .clients[0].ip) + top_client_raw=$(GetFTLData "/stats/top_clients" | jq --raw-output .clients[0].ip 2>/dev/null) fi } @@ -247,12 +264,17 @@ GetSystemInformation() { sysinfo=$(GetFTLData "/info/system") # System uptime - system_uptime_raw=$(echo "${sysinfo}" | jq .system.uptime ) + if [ "${sysinfo}" = 000 ]; then + # in case FTL connection is down, system_uptime_raw need to be set to 0 otherwise convertUptime() will complain + system_uptime_raw=0 + else + system_uptime_raw=$(echo "${sysinfo}" | jq .system.uptime 2>/dev/null) + fi # CPU temperature and unit - cpu_temp_raw=$(GetFTLData "/info/sensors" | jq .sensors[0].value) + cpu_temp_raw=$(GetFTLData "/info/sensors" | jq .sensors[0].value 2>/dev/null) cpu_temp=$(printf "%.1f" "${cpu_temp_raw}") - temp_unit=$(GetFTLData "/info/sensors" | jq --raw-output .sensors[0].unit) + temp_unit=$(GetFTLData "/info/sensors" | jq --raw-output .sensors[0].unit 2>/dev/null) # Temp + Unit if [ "${temp_unit}" = "C" ]; then @@ -286,22 +308,22 @@ GetSystemInformation() { fi # CPU, load, heatmap - core_count=$(echo "${sysinfo}" | jq .system.cpu.nprocs) - cpu_load_1=$(printf %.2f "$(echo "${sysinfo}" | jq .system.cpu.load.raw[0])") - cpu_load_5=$(printf %.2f "$(echo "${sysinfo}" | jq .system.cpu.load.raw[1])") - cpu_load_15=$(printf %.2f "$(echo "${sysinfo}" | jq .system.cpu.load.raw[2])") + core_count=$(echo "${sysinfo}" | jq .system.cpu.nprocs 2>/dev/null) + cpu_load_1=$(printf %.2f "$(echo "${sysinfo}" | jq .system.cpu.load.raw[0] 2>/dev/null)") + cpu_load_5=$(printf %.2f "$(echo "${sysinfo}" | jq .system.cpu.load.raw[1] 2>/dev/null)") + cpu_load_15=$(printf %.2f "$(echo "${sysinfo}" | jq .system.cpu.load.raw[2] 2>/dev/null)") cpu_load_1_heatmap=$(HeatmapGenerator "${cpu_load_1}" "${core_count}") cpu_load_5_heatmap=$(HeatmapGenerator "${cpu_load_5}" "${core_count}") cpu_load_15_heatmap=$(HeatmapGenerator "${cpu_load_15}" "${core_count}") - cpu_percent=$(printf %.1f "$(echo "${sysinfo}" | jq .system.cpu.load.percent[0])") + cpu_percent=$(printf %.1f "$(echo "${sysinfo}" | jq .system.cpu.load.percent[0] 2>/dev/null)") # Memory use, heatmap and bar - memory_percent_raw="$(echo "${sysinfo}" | jq '.system.memory.ram."%used"')" + memory_percent_raw="$(echo "${sysinfo}" | jq '.system.memory.ram."%used"' 2>/dev/null)" memory_percent=$(printf %.1f "${memory_percent_raw}") memory_heatmap="$(HeatmapGenerator "${memory_percent}")" # Get device model - sys_model="$(GetFTLData "/info/host" | jq --raw-output .host.model)" + sys_model="$(GetFTLData "/info/host" | jq --raw-output .host.model 2>/dev/null)" # DOCKER_VERSION is set during GetVersionInformation, so this needs to run first during startup if [ ! "${DOCKER_VERSION}" = "null" ]; then @@ -322,40 +344,40 @@ GetNetworkInformation() { config=$(GetFTLData "/config") # Get pi IPv4 address of the default interface - pi_ip4_addrs="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv4[]' | wc -w)" + pi_ip4_addrs="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv4[]' 2>/dev/null | wc -w)" if [ "${pi_ip4_addrs}" -eq 0 ]; then # No IPv4 address available pi_ip4_addr="N/A" elif [ "${pi_ip4_addrs}" -eq 1 ]; then # One IPv4 address available - pi_ip4_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv4[0]')" + pi_ip4_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv4[0]' 2>/dev/null)" else # More than one IPv4 address available - pi_ip4_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv4[0]')+" + pi_ip4_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv4[0]' 2>/dev/null)+" fi # Get pi IPv6 address of the default interface - pi_ip6_addrs="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv6[]' | wc -w)" + pi_ip6_addrs="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv6[]' 2>/dev/null | wc -w)" if [ "${pi_ip6_addrs}" -eq 0 ]; then # No IPv6 address available pi_ip6_addr="N/A" ipv6_check_box=${check_box_bad} elif [ "${pi_ip6_addrs}" -eq 1 ]; then # One IPv6 address available - pi_ip6_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv6[0]' | cut -f1 -d "%" )" + pi_ip6_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv6[0]' 2>/dev/null | cut -f1 -d "%" )" ipv6_check_box=${check_box_good} else # More than one IPv6 address available - pi_ip6_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv6[0]' | cut -f1 -d "%" )+" + pi_ip6_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv6[0]' 2>/dev/null | cut -f1 -d "%" )+" ipv6_check_box=${check_box_good} fi # Is Pi-Hole acting as the DHCP server? - DHCP_ACTIVE="$(echo "${config}" | jq .config.dnsmasq.dhcp.active)" + DHCP_ACTIVE="$(echo "${config}" | jq .config.dnsmasq.dhcp.active 2>/dev/null )" if [ "${DHCP_ACTIVE}" = "true" ]; then - DHCP_START="$(echo "${config}" | jq --raw-output .config.dnsmasq.dhcp.start)" - DHCP_END="$(echo "${config}" | jq --raw-output .config.dnsmasq.dhcp.end)" + DHCP_START="$(echo "${config}" | jq --raw-output .config.dnsmasq.dhcp.start 2>/dev/null)" + DHCP_END="$(echo "${config}" | jq --raw-output .config.dnsmasq.dhcp.end 2>/dev/null)" dhcp_status="Enabled" dhcp_info=" Range: ${DHCP_START} - ${DHCP_END}" @@ -363,7 +385,7 @@ GetNetworkInformation() { dhcp_check_box=${check_box_good} # Is DHCP handling IPv6? - DHCP_IPv6="$(echo "${config}" | jq --raw-output .config.dnsmasq.dhcp.ipv6)" + DHCP_IPv6="$(echo "${config}" | jq --raw-output .config.dnsmasq.dhcp.ipv6 2>/dev/null)" if [ "${DHCP_IPv6}" = "true" ]; then dhcp_ipv6_status="Enabled" dhcp_ipv6_heatmap=${green_text} @@ -378,7 +400,7 @@ GetNetworkInformation() { dhcp_heatmap=${red_text} dhcp_check_box=${check_box_bad} - GATEWAY="$(GetFTLData "/network/gateway" | jq --raw-output .address)" + GATEWAY="$(GetFTLData "/network/gateway" | jq --raw-output .address 2>/dev/null)" dhcp_info=" Router: ${GATEWAY}" dhcp_ipv6_status="N/A" dhcp_ipv6_heatmap=${yellow_text} @@ -386,11 +408,11 @@ GetNetworkInformation() { fi # Get hostname - pi_hostname="$(GetFTLData "/info/host" | jq --raw-output .host.uname.nodename)" + pi_hostname="$(GetFTLData "/info/host" | jq --raw-output .host.uname.nodename 2>/dev/null)" full_hostname=${pi_hostname} # when PI-hole is the DHCP server, append the domain to the hostname if [ "${DHCP_ACTIVE}" = "true" ]; then - PIHOLE_DOMAIN="$(echo "${config}" | jq --raw-output .config.dnsmasq.domain)" + PIHOLE_DOMAIN="$(echo "${config}" | jq --raw-output .config.dnsmasq.domain 2>/dev/null)" if [ -n "${PIHOLE_DOMAIN}" ]; then count=${pi_hostname}"."${PIHOLE_DOMAIN} count=${#count} @@ -401,7 +423,7 @@ GetNetworkInformation() { fi # Get the number of configured upstream DNS servers - dns_count="$(echo "${config}" | jq --raw-output .config.dnsmasq.upstreams[] | sed '/^\s*$/d' | wc -l)" + dns_count="$(echo "${config}" | jq --raw-output .config.dnsmasq.upstreams[] 2>/dev/null | sed '/^\s*$/d' | wc -l)" # if there's only one DNS server if [ "${dns_count}" -eq 1 ]; then dns_information="1 server" @@ -411,7 +433,7 @@ GetNetworkInformation() { # DNSSEC - DNSSEC="$(echo "${config}" | jq .config.dnsmasq.dnssec)" + DNSSEC="$(echo "${config}" | jq .config.dnsmasq.dnssec 2>/dev/null)" if [ "${DNSSEC}" = "true" ]; then dnssec_status="Enabled" dnssec_heatmap=${green_text} @@ -421,7 +443,7 @@ GetNetworkInformation() { fi # Conditional forwarding - CONDITIONAL_FORWARDING="$(echo "${config}" | jq .config.dnsmasq.rev_server.active)" + CONDITIONAL_FORWARDING="$(echo "${config}" | jq .config.dnsmasq.rev_server.active 2>/dev/null)" if [ "${CONDITIONAL_FORWARDING}" = "true" ]; then conditional_forwarding_status="Enabled" conditional_forwarding_heatmap=${green_text} @@ -431,30 +453,27 @@ GetNetworkInformation() { fi # Default interface data - iface_name="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .name')" - tx_bytes="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .tx.num')" - tx_bytes_unit="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .tx.unit')" + iface_name="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .name' 2>/dev/null)" + tx_bytes="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .tx.num' 2>/dev/null)" + tx_bytes_unit="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .tx.unit' 2>/dev/null)" tx_bytes=$(printf "%.1f %b" "${tx_bytes}" "${tx_bytes_unit}") - rx_bytes="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .rx.num')" - rx_bytes_unit="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .rx.unit')" + rx_bytes="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .rx.num' 2>/dev/null)" + rx_bytes_unit="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .rx.unit' 2>/dev/null)" rx_bytes=$(printf "%.1f %b" "${rx_bytes}" "${rx_bytes_unit}") } GetPiholeInformation() { sysinfo=$(GetFTLData "/info/ftl") - # Get FTL's current PID - ftlPID="$(echo "${sysinfo}" | jq .ftl.pid)" - - # If FTL is not running (ftlPID is -1), set all variables to "not running" - ftl_down_flag=false - if [ "${ftlPID}" = "-1" ]; then - ftl_status="Not running" + # If FTL is not running (sysinfo is 000), set all variables to "not running" + connection_down_flag=false + if [ "${sysinfo}" = "000" ]; then + ftl_status="No connection" ftl_heatmap=${red_text} ftl_check_box=${check_box_bad} # set flag to change the status message in SetStatusMessage() - ftl_down_flag=true + connection_down_flag=true ftl_cpu="N/A" ftl_mem_percentage="N/A" else @@ -462,19 +481,21 @@ GetPiholeInformation() { ftl_heatmap=${green_text} ftl_check_box=${check_box_good} # Get FTL CPU and memory usage - ftl_cpu_raw="$(echo "${sysinfo}" | jq '.ftl."%cpu"')" - ftl_mem_percentage_raw="$(echo "${sysinfo}" | jq '.ftl."%mem"')" + ftl_cpu_raw="$(echo "${sysinfo}" | jq '.ftl."%cpu"' 2>/dev/null)" + ftl_mem_percentage_raw="$(echo "${sysinfo}" | jq '.ftl."%mem"' 2>/dev/null)" ftl_cpu="$(printf "%.1f" "${ftl_cpu_raw}")%" ftl_mem_percentage="$(printf "%.1f" "${ftl_mem_percentage_raw}")%" # Get Pi-hole (blocking) status - ftl_dns_port=$(GetFTLData "/config" | jq .config.dnsmasq.port) + ftl_dns_port=$(GetFTLData "/config" | jq .config.dnsmasq.port 2>/dev/null) + # Get FTL's current PID + ftlPID="$(echo "${sysinfo}" | jq .ftl.pid 2>/dev/null)" fi - # ${ftl_dns_port} == 0 DNS server part of dnsmasq disabled, ${ftl_status} == "Not running" no ftlPID found + # ${ftl_dns_port} == 0 DNS server part of dnsmasq disabled dns_down_flag=false - if [ "${ftl_dns_port}" = 0 ] || [ "${ftl_status}" = "Not running" ]; then + if [ "${ftl_dns_port}" = 0 ] || [ "${ftl_status}" = "No connection" ]; then dns_status="DNS offline" dns_heatmap=${red_text} dns_check_box=${check_box_bad} @@ -494,11 +515,11 @@ GetVersionInformation() { # Gather DOCKER version information... # returns "null" if not running Pi-hole in Docker container - DOCKER_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.docker.local)" + DOCKER_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.docker.local 2>/dev/null)" # If PADD is running inside docker, immediately return without checking for updated component versions if [ ! "${DOCKER_VERSION}" = "null" ] ; then - GITHUB_DOCKER_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.docker.remote)" + GITHUB_DOCKER_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.docker.remote 2>/dev/null)" docker_version_converted="$(VersionConverter "${DOCKER_VERSION}")" docker_version_latest_converted="$(VersionConverter "${GITHUB_DOCKER_VERSION}")" @@ -512,11 +533,11 @@ GetVersionInformation() { fi # Gather core version information... - CORE_BRANCH="$(echo "${versions_raw}" | jq --raw-output .version.core.local.branch)" - CORE_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.core.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_CORE_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.core.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - CORE_HASH="$(echo "${versions_raw}" | jq --raw-output .version.core.local.hash)" - GITHUB_CORE_HASH="$(echo "${versions_raw}" | jq --raw-output .version.core.remote.hash)" + CORE_BRANCH="$(echo "${versions_raw}" | jq --raw-output .version.core.local.branch 2>/dev/null)" + CORE_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.core.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_CORE_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.core.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + CORE_HASH="$(echo "${versions_raw}" | jq --raw-output .version.core.local.hash 2>/dev/null)" + GITHUB_CORE_HASH="$(echo "${versions_raw}" | jq --raw-output .version.core.remote.hash 2>/dev/null)" if [ "${CORE_BRANCH}" = "master" ]; then core_version_converted="$(VersionConverter "${CORE_VERSION}")" @@ -550,14 +571,14 @@ GetVersionInformation() { fi # Gather web version information... - WEB_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.web.local.version)" + WEB_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.web.local.version 2>/dev/null)" if [ ! "$WEB_VERSION" = "null" ]; then - WEB_BRANCH="$(echo "${versions_raw}" | jq --raw-output .version.web.local.branch)" - WEB_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.web.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_WEB_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.web.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - WEB_HASH="$(echo "${versions_raw}" | jq --raw-output .version.web.local.hash)" - GITHUB_WEB_HASH="$(echo "${versions_raw}" | jq --raw-output .version.web.remote.hash)" + WEB_BRANCH="$(echo "${versions_raw}" | jq --raw-output .version.web.local.branch 2>/dev/null)" + WEB_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.web.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_WEB_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.web.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + WEB_HASH="$(echo "${versions_raw}" | jq --raw-output .version.web.local.hash 2>/dev/null)" + GITHUB_WEB_HASH="$(echo "${versions_raw}" | jq --raw-output .version.web.remote.hash 2>/dev/null)" if [ "${WEB_BRANCH}" = "master" ]; then web_version_converted="$(VersionConverter "${WEB_VERSION}")" @@ -597,11 +618,11 @@ GetVersionInformation() { fi # Gather FTL version information... - FTL_BRANCH="$(echo "${versions_raw}" | jq --raw-output .version.ftl.local.branch)" - FTL_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.ftl.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_FTL_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.ftl.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - FTL_HASH="$(echo "${versions_raw}" | jq --raw-output .version.ftl.local.hash)" - GITHUB_FTL_HASH="$(echo "${versions_raw}" | jq --raw-output .version.ftl.remote.hash)" + FTL_BRANCH="$(echo "${versions_raw}" | jq --raw-output .version.ftl.local.branch 2>/dev/null)" + FTL_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.ftl.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_FTL_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.ftl.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + FTL_HASH="$(echo "${versions_raw}" | jq --raw-output .version.ftl.local.hash 2>/dev/null)" + GITHUB_FTL_HASH="$(echo "${versions_raw}" | jq --raw-output .version.ftl.remote.hash 2>/dev/null)" if [ "${FTL_BRANCH}" = "master" ]; then @@ -744,7 +765,7 @@ SetStatusMessage() { full_status="${full_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" mega_status="${mega_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" - elif [ "${ftl_down_flag}" = true ]; then + elif [ "${connection_down_flag}" = true ]; then # Check if FTL is down pico_status=${pico_status_ftl_down} mini_status=${mini_status_ftl_down} @@ -1432,6 +1453,14 @@ NormalPADD() { # Start getting our information for next round now=$(date +%s) + # check if a new authentication is required (e.g. after connection to FTL has re-established) + # GetFTLData() will return a 401 if a 401 http status code is returned + # as $password should be set already, PADD should automatically re-authenticate + authenthication_required=$(GetFTLData "/info/ftl") + if [ "${authenthication_required}" = 401 ]; then + ChallengeResponse + fi + # Get uptime, CPU load, temp, etc. every 5 seconds if [ $((now - LastCheckSystemInformation)) -ge 5 ]; then GetSystemInformation From ed2de7807eaa24fc92b42761c5a4652b554eea34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sun, 12 Mar 2023 22:58:06 +0100 Subject: [PATCH 22/96] Adjust endoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/padd.sh b/padd.sh index ba308ee..9f738b6 100755 --- a/padd.sh +++ b/padd.sh @@ -223,7 +223,7 @@ GetFTLData() { GetSummaryInformation() { summary=$(GetFTLData "/stats/summary") - cache_info=$(GetFTLData "/dns/cache") + cache_info=$(GetFTLData "/info/metrics") ftl_info=$(GetFTLData "/info/ftl") dns_blocking=$(GetFTLData "/dns/blocking") @@ -243,9 +243,9 @@ GetSummaryInformation() { ads_percentage_today_raw=$(echo "$summary" | jq .queries.percent_blocked 2>/dev/null) ads_percentage_today=$(printf "%.1f" "${ads_percentage_today_raw}") - cache_size=$(echo "$cache_info" | jq .cache.size 2>/dev/null) - cache_evictions=$(echo "$cache_info" | jq .cache.evicted 2>/dev/null) - cache_inserts=$(echo "$cache_info"| jq .cache.inserted 2>/dev/null) + cache_size=$(echo "$cache_info" | jq .metrics.dns.cache.size 2>/dev/null) + cache_evictions=$(echo "$cache_info" | jq .metrics.dns.cache.evicted 2>/dev/null) + cache_inserts=$(echo "$cache_info"| jq .metrics.dns.cache.inserted 2>/dev/null) latest_blocked_raw=$(GetFTLData "/stats/recent_blocked?show=1" | jq --raw-output .blocked[0] 2>/dev/null) @@ -813,7 +813,7 @@ PrintLogo() { if [ ! "${DOCKER_VERSION}" = "null" ]; then version_info="Docker ${docker_version_heatmap}${DOCKER_VERSION}${reset_text}" else - version_info="Pi-hole® ${core_version_heatmap}${CORE_VERSION}${reset_text}, Web ${web_version_heatmap}${WEB_VERSION}${reset_text}, FTL ${ftl_version_heatmap}${FTL_VERSION}" + version_info="Pi-hole® ${core_version_heatmap}${CORE_VERSION}${reset_text}, Web ${web_version_heatmap}${WEB_VERSION}${reset_text}, FTL ${ftl_version_heatmap}${FTL_VERSION}${reset_text}" fi # Screen size checks @@ -846,7 +846,7 @@ PrintDashboard() { if [ ! "${DOCKER_VERSION}" = "null" ]; then version_info="Docker ${docker_version_heatmap}${DOCKER_VERSION}${reset_text}" else - version_info="Pi-hole® ${core_version_heatmap}${CORE_VERSION}${reset_text}, Web ${web_version_heatmap}${WEB_VERSION}${reset_text}, FTL ${ftl_version_heatmap}${FTL_VERSION}" + version_info="Pi-hole® ${core_version_heatmap}${CORE_VERSION}${reset_text}, Web ${web_version_heatmap}${WEB_VERSION}${reset_text}, FTL ${ftl_version_heatmap}${FTL_VERSION}${reset_text}" fi # Move cursor to (0,0). printf '\e[H' From 94032c9574705c01a7719a435ee7f47f9811ad36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 13 Mar 2023 13:51:57 +0100 Subject: [PATCH 23/96] Account for cpu_temp_sensor returning null MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/padd.sh b/padd.sh index 9f738b6..e732cd3 100755 --- a/padd.sh +++ b/padd.sh @@ -272,9 +272,10 @@ GetSystemInformation() { fi # CPU temperature and unit - cpu_temp_raw=$(GetFTLData "/info/sensors" | jq .sensors[0].value 2>/dev/null) + # in case .sensors.cpu_temp returns 'null' we substitute with 0 + cpu_temp_raw=$(GetFTLData "/info/sensors" | jq '(.sensors.cpu_temp // 0)' 2>/dev/null) cpu_temp=$(printf "%.1f" "${cpu_temp_raw}") - temp_unit=$(GetFTLData "/info/sensors" | jq --raw-output .sensors[0].unit 2>/dev/null) + temp_unit=$(GetFTLData "/info/sensors" | jq --raw-output .sensors.unit 2>/dev/null) # Temp + Unit if [ "${temp_unit}" = "C" ]; then From b1784466968c75567e4df44afb6bdf98214b05aa Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 24 May 2023 20:41:48 +0200 Subject: [PATCH 24/96] Show a running PADD as "PADD v4.0.0" instead of "curl/7.81.0" on the web interface Signed-off-by: DL6ER --- padd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/padd.sh b/padd.sh index e732cd3..17eed20 100755 --- a/padd.sh +++ b/padd.sh @@ -185,7 +185,7 @@ ChallengeResponse() { # Send response & get session response challenge="$(curl --silent -X GET "http://${URL}:${PORT}/${APIPATH}/auth" | jq --raw-output .challenge 2>/dev/null)" response="$(printf "%b" "${challenge}:${pwhash}" | sha256sum | sed 's/\s.*$//')" - sessionResponse="$(curl --silent -X POST "http://${URL}:${PORT}/${APIPATH}/auth" --data "{\"response\":\"${response}\"}" )" + sessionResponse="$(curl --silent -X POST "http://${URL}:${PORT}/${APIPATH}/auth" --user-agent "PADD ${padd_version}" --data "{\"response\":\"${response}\"}" )" if [ -z "${sessionResponse}" ]; then moveXOffset; echo "No response from FTL server. Please check connectivity and use the options to set the API URL" From 716897b8ed1a0e8768e4ca48fd6e7d9cb7bda0a6 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Tue, 30 May 2023 21:25:37 +0200 Subject: [PATCH 25/96] Switch to the proven memory-hard password-hashing alogorithm BALLOON Signed-off-by: DL6ER --- padd.sh | 44 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/padd.sh b/padd.sh index e83b16f..9b28ea0 100755 --- a/padd.sh +++ b/padd.sh @@ -118,7 +118,7 @@ TestAPIAvailability() { availabilityResonse=$(curl -s -o /dev/null -w "%{http_code}" "http://${URL}:${PORT}/${APIPATH}/auth") # test if http status code was 200 (OK) - if [ "${availabilityResonse}" = 200 ]; then + if [ "${availabilityResonse}" = 200 ] || [ "${availabilityResonse}" = 401 ]; then moveXOffset; printf "%b" "API available at: http://${URL}:${PORT}/${APIPATH}\n" else moveXOffset; echo "API not available at: http://${URL}:${PORT}/${APIPATH}" @@ -129,7 +129,7 @@ TestAPIAvailability() { Authenthication() { # Try to authenticate - ChallengeResponse + LoginAPI while [ "${validSession}" = false ] || [ -z "${validSession}" ] ; do moveXOffset; echo "Authentication failed." @@ -145,7 +145,7 @@ Authenthication() { moveXOffset; secretRead; printf '\n' # Try to authenticate again - ChallengeResponse + LoginAPI done # Loop exited, authentication was successful @@ -170,22 +170,8 @@ DeleteSession() { } -ChallengeResponse() { - # Challenge-response authentication - local response - - # Compute password hash from user password - # Compute password hash twice to avoid rainbow table vulnerability - hash1=$(printf "%b" "$password" | sha256sum | sed 's/\s.*$//') - pwhash=$(printf "%b" "$hash1" | sha256sum | sed 's/\s.*$//') - - - # Get challenge from FTL - # Calculate response based on challenge and password hash - # Send response & get session response - challenge="$(curl --silent -X GET "http://${URL}:${PORT}/${APIPATH}/auth" | jq --raw-output .challenge 2>/dev/null)" - response="$(printf "%b" "${challenge}:${pwhash}" | sha256sum | sed 's/\s.*$//')" - sessionResponse="$(curl --silent -X POST "http://${URL}:${PORT}/${APIPATH}/auth" --user-agent "PADD ${padd_version}" --data "{\"response\":\"${response}\"}" )" +LoginAPI() { + sessionResponse="$(curl --silent -X POST "http://${URL}:${PORT}/${APIPATH}/auth" --user-agent "PADD ${padd_version}" --data "{\"password\":\"${password}\"}" )" if [ -z "${sessionResponse}" ]; then moveXOffset; echo "No response from FTL server. Please check connectivity and use the options to set the API URL" @@ -374,11 +360,11 @@ GetNetworkInformation() { fi # Is Pi-Hole acting as the DHCP server? - DHCP_ACTIVE="$(echo "${config}" | jq .config.dnsmasq.dhcp.active 2>/dev/null )" + DHCP_ACTIVE="$(echo "${config}" | jq .config.dns.dhcp.active 2>/dev/null )" if [ "${DHCP_ACTIVE}" = "true" ]; then - DHCP_START="$(echo "${config}" | jq --raw-output .config.dnsmasq.dhcp.start 2>/dev/null)" - DHCP_END="$(echo "${config}" | jq --raw-output .config.dnsmasq.dhcp.end 2>/dev/null)" + DHCP_START="$(echo "${config}" | jq --raw-output .config.dns.dhcp.start 2>/dev/null)" + DHCP_END="$(echo "${config}" | jq --raw-output .config.dns.dhcp.end 2>/dev/null)" dhcp_status="Enabled" dhcp_info=" Range: ${DHCP_START} - ${DHCP_END}" @@ -386,7 +372,7 @@ GetNetworkInformation() { dhcp_check_box=${check_box_good} # Is DHCP handling IPv6? - DHCP_IPv6="$(echo "${config}" | jq --raw-output .config.dnsmasq.dhcp.ipv6 2>/dev/null)" + DHCP_IPv6="$(echo "${config}" | jq --raw-output .config.dns.dhcp.ipv6 2>/dev/null)" if [ "${DHCP_IPv6}" = "true" ]; then dhcp_ipv6_status="Enabled" dhcp_ipv6_heatmap=${green_text} @@ -413,7 +399,7 @@ GetNetworkInformation() { full_hostname=${pi_hostname} # when PI-hole is the DHCP server, append the domain to the hostname if [ "${DHCP_ACTIVE}" = "true" ]; then - PIHOLE_DOMAIN="$(echo "${config}" | jq --raw-output .config.dnsmasq.domain 2>/dev/null)" + PIHOLE_DOMAIN="$(echo "${config}" | jq --raw-output .config.dns.domain 2>/dev/null)" if [ -n "${PIHOLE_DOMAIN}" ]; then count=${pi_hostname}"."${PIHOLE_DOMAIN} count=${#count} @@ -424,7 +410,7 @@ GetNetworkInformation() { fi # Get the number of configured upstream DNS servers - dns_count="$(echo "${config}" | jq --raw-output .config.dnsmasq.upstreams[] 2>/dev/null | sed '/^\s*$/d' | wc -l)" + dns_count="$(echo "${config}" | jq --raw-output .config.dns.upstreams[] 2>/dev/null | sed '/^\s*$/d' | wc -l)" # if there's only one DNS server if [ "${dns_count}" -eq 1 ]; then dns_information="1 server" @@ -434,7 +420,7 @@ GetNetworkInformation() { # DNSSEC - DNSSEC="$(echo "${config}" | jq .config.dnsmasq.dnssec 2>/dev/null)" + DNSSEC="$(echo "${config}" | jq .config.dns.dnssec 2>/dev/null)" if [ "${DNSSEC}" = "true" ]; then dnssec_status="Enabled" dnssec_heatmap=${green_text} @@ -444,7 +430,7 @@ GetNetworkInformation() { fi # Conditional forwarding - CONDITIONAL_FORWARDING="$(echo "${config}" | jq .config.dnsmasq.rev_server.active 2>/dev/null)" + CONDITIONAL_FORWARDING="$(echo "${config}" | jq .config.dns.rev_server.active 2>/dev/null)" if [ "${CONDITIONAL_FORWARDING}" = "true" ]; then conditional_forwarding_status="Enabled" conditional_forwarding_heatmap=${green_text} @@ -487,7 +473,7 @@ GetPiholeInformation() { ftl_cpu="$(printf "%.1f" "${ftl_cpu_raw}")%" ftl_mem_percentage="$(printf "%.1f" "${ftl_mem_percentage_raw}")%" # Get Pi-hole (blocking) status - ftl_dns_port=$(GetFTLData "/config" | jq .config.dnsmasq.port 2>/dev/null) + ftl_dns_port=$(GetFTLData "/config" | jq .config.dns.port 2>/dev/null) # Get FTL's current PID ftlPID="$(echo "${sysinfo}" | jq .ftl.pid 2>/dev/null)" fi @@ -1495,7 +1481,7 @@ NormalPADD() { # as $password should be set already, PADD should automatically re-authenticate authenthication_required=$(GetFTLData "/info/ftl") if [ "${authenthication_required}" = 401 ]; then - ChallengeResponse + LoginAPI fi # Get uptime, CPU load, temp, etc. every 5 seconds From 57b102c909ef61c43d558ddf10f461a8a8219d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 31 Jul 2023 23:00:12 +0200 Subject: [PATCH 26/96] Change default API port to 80 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/padd.sh b/padd.sh index a9bdc66..78e81fb 100755 --- a/padd.sh +++ b/padd.sh @@ -106,7 +106,7 @@ ConstructAPI() { URL=127.0.0.1 fi if [ -z "${PORT}" ]; then - PORT=8080 + PORT=80 fi if [ -z "${APIPATH}" ]; then APIPATH=api @@ -1583,7 +1583,7 @@ DisplayHelp() { ::: -yoff [num] set the y-offset, reference is the upper left corner, disables auto-centering ::: ::: --server url or address of your Pi-hole (default: 127.0.0.1) -::: --port port of your Pi-hole's API (default: 8080) +::: --port port of your Pi-hole's API (default: 80) ::: --api path where your Pi-hole's API is hosted (default: api) ::: --secret your Pi-hole's password, required to access the API ::: -j, --json output stats as JSON formatted string and exit and exit From 36257d1deb9c416472d6c198312300c45f06a602 Mon Sep 17 00:00:00 2001 From: RD WebDesign Date: Mon, 31 Jul 2023 18:46:56 -0300 Subject: [PATCH 27/96] Add on the help text the missing dash for xoff and yoff options Signed-off-by: RD WebDesign --- padd.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/padd.sh b/padd.sh index 78e81fb..d1490f9 100755 --- a/padd.sh +++ b/padd.sh @@ -1579,8 +1579,8 @@ DisplayHelp() { ::: ::: ::: Options: -::: -xoff [num] set the x-offset, reference is the upper left corner, disables auto-centering -::: -yoff [num] set the y-offset, reference is the upper left corner, disables auto-centering +::: --xoff [num] set the x-offset, reference is the upper left corner, disables auto-centering +::: --yoff [num] set the y-offset, reference is the upper left corner, disables auto-centering ::: ::: --server url or address of your Pi-hole (default: 127.0.0.1) ::: --port port of your Pi-hole's API (default: 80) From 794d7b0459360a3e3c4cf308727786e0c225011c Mon Sep 17 00:00:00 2001 From: RD WebDesign Date: Mon, 31 Jul 2023 19:09:16 -0300 Subject: [PATCH 28/96] Fix spellcheck and a few spaces Signed-off-by: RD WebDesign --- padd.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/padd.sh b/padd.sh index d1490f9..ef45660 100755 --- a/padd.sh +++ b/padd.sh @@ -157,7 +157,7 @@ DeleteSession() { # if a valid Session exists (no password required or successful authenthication) and # SID is not null (successful authenthication only), delete the session if [ "${validSession}" = true ] && [ ! "${SID}" = null ]; then - # Try to delte the session. Omitt the output, but get the http status code + # Try to delete the session. Omit the output, but get the http status code deleteResponse=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE "http://${URL}:${PORT}/${APIPATH}/auth" -H "Accept: application/json" -H "sid: ${SID}") printf "\n\n" @@ -190,7 +190,7 @@ GetFTLData() { # status are the last 3 characters status=$(printf %s "${response#"${response%???}"}") - # data is everything from repsonse without the last 3 characters + # data is everything from response without the last 3 characters data=$(printf %s "${response%???}") if [ "${status}" = 200 ]; then @@ -1214,8 +1214,8 @@ truncateString() { fi } -# Converts seconds to days, hours, minuts -#https://unix.stackexchange.com/a/338844 +# Converts seconds to days, hours, minutes +# https://unix.stackexchange.com/a/338844 convertUptime() { # shellcheck disable=SC2016 eval "echo $(date -ud "@$1" +'$((%s/3600/24)) days, %H hours, %M minutes')" @@ -1233,12 +1233,12 @@ secretRead() { # This workaround changes the terminal characteristics to not echo input and later rests this option # credits https://stackoverflow.com/a/4316765 - # showing astrix instead of password + # showing asterisk instead of password # https://stackoverflow.com/a/24600839 # https://unix.stackexchange.com/a/464963 stty -echo # do not echo user input - stty -icanon min 1 time 0 # disable cannonical mode https://man7.org/linux/man-pages/man3/termios.3.html + stty -icanon min 1 time 0 # disable canonical mode https://man7.org/linux/man-pages/man3/termios.3.html unset password unset key @@ -1283,7 +1283,7 @@ OutputJSON() { # Construct FTL's API address depending on the arguments supplied ConstructAPI - # Test if the authentication endpoint is availabe + # Test if the authentication endpoint is available TestAPIAvailability # Authenticate with the FTL server printf "%b" "Establishing connection with FTL...\n" @@ -1307,7 +1307,7 @@ ShowVersion() { # Construct FTL's API address depending on the arguments supplied ConstructAPI - # Test if the authentication endpoint is availabe + # Test if the authentication endpoint is available TestAPIAvailability # Authenticate with the FTL server printf "%b" "Establishing connection with FTL...\n" @@ -1343,7 +1343,7 @@ StartupRoutine(){ moveXOffset; PrintLogo "$1" moveXOffset; printf "%b" "START-UP ===========\n" - # Test if the authentication endpoint is availabe + # Test if the authentication endpoint is available TestAPIAvailability # Authenticate with the FTL server @@ -1376,7 +1376,7 @@ StartupRoutine(){ elif [ "$1" = "mini" ]; then moveXOffset; PrintLogo "$1" moveXOffset; echo "START UP =====================" - # Test if the authentication endpoint is availabe + # Test if the authentication endpoint is available TestAPIAvailability # Authenticate with the FTL server moveXOffset; printf "%b" "Establishing connection with FTL...\n" @@ -1410,7 +1410,7 @@ StartupRoutine(){ moveXOffset; echo "START UP ===================================================" fi - # Test if the authentication endpoint is availabe + # Test if the authentication endpoint is available TestAPIAvailability # Authenticate with the FTL server @@ -1615,7 +1615,7 @@ CleanExit() { # reset trap for all signals to not interrupt clean_tempfiles() on any next signal trap '' EXIT INT QUIT TERM - # restore terminal settings if they have been changed (e.g. user cancled script while at password input prompt) + # restore terminal settings if they have been changed (e.g. user canceled script while at password input prompt) if [ "$(stty -g)" != "${stty_orig}" ]; then stty "${stty_orig}" fi From 4a69af0dd201cb87dff77c23cde38e6c6eebce00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 2 Aug 2023 21:31:02 +0200 Subject: [PATCH 29/96] When running locally derive port from FTL itself MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/padd.sh b/padd.sh index 78e81fb..58a2d4e 100755 --- a/padd.sh +++ b/padd.sh @@ -104,6 +104,9 @@ ConstructAPI() { # If no arguments were supplied set them to default if [ -z "${URL}" ]; then URL=127.0.0.1 + # when no $URL is set we assume PADD is running locally and we can get the port value from FTL directly + PORT="$(pihole-FTL --config webserver.port)" + PORT="${PORT%%,*}" fi if [ -z "${PORT}" ]; then PORT=80 @@ -1231,7 +1234,7 @@ secretRead() { # `-n` option (reading n chars) - # This workaround changes the terminal characteristics to not echo input and later rests this option + # This workaround changes the terminal characteristics to not echo input and later resets this option # credits https://stackoverflow.com/a/4316765 # showing astrix instead of password # https://stackoverflow.com/a/24600839 From b67b0fb2e0db69e53db1773b8b2115baa9d4e0d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 2 Aug 2023 21:44:01 +0200 Subject: [PATCH 30/96] Remove space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/padd.sh b/padd.sh index 58a2d4e..fcdecc9 100755 --- a/padd.sh +++ b/padd.sh @@ -105,7 +105,7 @@ ConstructAPI() { if [ -z "${URL}" ]; then URL=127.0.0.1 # when no $URL is set we assume PADD is running locally and we can get the port value from FTL directly - PORT="$(pihole-FTL --config webserver.port)" + PORT="$(pihole-FTL --config webserver.port)" PORT="${PORT%%,*}" fi if [ -z "${PORT}" ]; then From 13dbce323fa97144f9ab49ad0beeb1d85dba3c27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 21 Oct 2023 10:42:23 +0000 Subject: [PATCH 31/96] Bump actions/checkout from 4.1.0 to 4.1.1 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.0 to 4.1.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.1.0...v4.1.1) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codespell.yml | 2 +- .github/workflows/editorconfig-checker.yml | 2 +- .github/workflows/stale.yml | 2 +- .github/workflows/sync-back-to-dev.yml | 2 +- .github/workflows/version_bump.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 8f5f6aa..cbd7f85 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Spell-Checking uses: codespell-project/actions-codespell@master diff --git a/.github/workflows/editorconfig-checker.yml b/.github/workflows/editorconfig-checker.yml index 9eff6db..807dc02 100644 --- a/.github/workflows/editorconfig-checker.yml +++ b/.github/workflows/editorconfig-checker.yml @@ -9,6 +9,6 @@ jobs: name: editorconfig-checker runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4.1.1 - uses: editorconfig-checker/action-editorconfig-checker@main # current tag v1.0.0 is really out-of-date - run: editorconfig-checker diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 5535c56..f0b4085 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Remove 'stale' label run: gh issue edit ${{ github.event.issue.number }} --remove-label ${{ env.stale_label }} env: diff --git a/.github/workflows/sync-back-to-dev.yml b/.github/workflows/sync-back-to-dev.yml index 6d59401..3d8b7c5 100644 --- a/.github/workflows/sync-back-to-dev.yml +++ b/.github/workflows/sync-back-to-dev.yml @@ -11,7 +11,7 @@ jobs: name: Syncing branches steps: - name: Checkout - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 - name: Opening pull request run: gh pr create -B development -H master --title 'Sync master back into development' --body 'Created by Github action' --label 'Internal' env: diff --git a/.github/workflows/version_bump.yml b/.github/workflows/version_bump.yml index 9d1d893..e0f95ee 100644 --- a/.github/workflows/version_bump.yml +++ b/.github/workflows/version_bump.yml @@ -19,7 +19,7 @@ jobs: echo "latest_tag=$LATEST_TAG" >> $GITHUB_ENV - name: Checkout code - uses: actions/checkout@v4.1.0 + uses: actions/checkout@v4.1.1 with: ref: 'development' From 9aee13872da35178bf0d110d6ae206d69de85361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sat, 2 Dec 2023 21:53:58 +0100 Subject: [PATCH 32/96] Use CHAOS TXT to connect to FTL's API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 95 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 37 deletions(-) diff --git a/padd.sh b/padd.sh index 4d69719..3f7e9de 100755 --- a/padd.sh +++ b/padd.sh @@ -100,32 +100,63 @@ padd_logo_retro_3="${bold_text}${green_text}| ${red_text}/${yellow_text}-${gre ############################################# FTL ################################################## -ConstructAPI() { - # If no arguments were supplied set them to default - if [ -z "${URL}" ]; then - URL=127.0.0.1 - # when no $URL is set we assume PADD is running locally and we can get the port value from FTL directly - PORT="$(pihole-FTL --config webserver.port)" - PORT="${PORT%%,*}" - fi - if [ -z "${PORT}" ]; then - PORT=80 - fi - if [ -z "${APIPATH}" ]; then - APIPATH=api - fi -} - TestAPIAvailability() { - availabilityResonse=$(curl -s -o /dev/null -w "%{http_code}" "http://${URL}:${PORT}/${APIPATH}/auth") + local chaos_api_list availabilityResonse - # test if http status code was 200 (OK) - if [ "${availabilityResonse}" = 200 ] || [ "${availabilityResonse}" = 401 ]; then - moveXOffset; printf "%b" "API available at: http://${URL}:${PORT}/${APIPATH}\n" + # Query the API URLs from FTL using CHAOS TXT + # The result is a space-separated enumeration of full URLs + # e.g., "http://localhost:80/api" or "https://domain.com:443/api" + if [ -z "${SERVER}" ]; then + # --server was not set, assuming we're running locally + chaos_api_list="$(dig +short chaos txt local.api.ftl @localhost)" else - moveXOffset; echo "API not available at: http://${URL}:${PORT}/${APIPATH}" - moveXOffset; echo "Exiting." + # --server was set, try to get response from there + chaos_api_list="$(dig +short chaos txt domain.api.ftl @"${SERVER}")" + fi + + # If the query was not successful, the variable is empty + if [ -z "${chaos_api_list}" ]; then + echo "API not available. Please check connectivity" + exit 1 + fi + + # Iterate over space-separated list of URLs + while [ -n "${chaos_api_list}" ]; do + # Get the first URL + API_URL="${chaos_api_list%% *}" + # Strip leading and trailing quotes + API_URL="${API_URL%\"}" + API_URL="${API_URL#\"}" + + # Test if the API is available at this URL + availabilityResonse=$(curl -skS -o /dev/null -w "%{http_code}" "${API_URL}auth") + + # Test if http status code was 200 (OK) or 401 (authentication required) + if [ ! "${availabilityResonse}" = 200 ] && [ ! "${availabilityResonse}" = 401 ]; then + # API is not available at this port/protocol combination + API_PORT="" + else + # API is available at this URL combination + break + fi + + # Remove the first URL from the list + local last_api_list + last_api_list="${chaos_api_list}" + chaos_api_list="${chaos_api_list#* }" + + # If the list did not change, we are at the last element + if [ "${last_api_list}" = "${chaos_api_list}" ]; then + # Remove the last element + chaos_api_list="" + fi + done + + # if API_PORT is empty, no working API port was found + if [ -n "${API_PORT}" ]; then + echo "API not available at: ${API_URL}" + echo "Exiting." exit 1 fi } @@ -161,7 +192,7 @@ DeleteSession() { # SID is not null (successful authenthication only), delete the session if [ "${validSession}" = true ] && [ ! "${SID}" = null ]; then # Try to delete the session. Omit the output, but get the http status code - deleteResponse=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE "http://${URL}:${PORT}/${APIPATH}/auth" -H "Accept: application/json" -H "sid: ${SID}") + deleteResponse=$(curl -skS -o /dev/null -w "%{http_code}" -X DELETE "${API_URL}/auth" -H "Accept: application/json" -H "sid: ${SID}") printf "\n\n" case "${deleteResponse}" in @@ -174,7 +205,7 @@ DeleteSession() { } LoginAPI() { - sessionResponse="$(curl --silent -X POST "http://${URL}:${PORT}/${APIPATH}/auth" --user-agent "PADD ${padd_version}" --data "{\"password\":\"${password}\"}" )" + sessionResponse="$(curl -skS -X POST "${API_URL}/auth" --user-agent "PADD ${padd_version}" --data "{\"password\":\"${password}\"}" )" if [ -z "${sessionResponse}" ]; then moveXOffset; echo "No response from FTL server. Please check connectivity and use the options to set the API URL" @@ -189,7 +220,7 @@ LoginAPI() { GetFTLData() { local response # get the data from querying the API as well as the http status code - response=$(curl -s -w "%{http_code}" -X GET "http://${URL}:${PORT}/${APIPATH}$1" -H "Accept: application/json" -H "sid: ${SID}" ) + response=$(curl -skS -w "%{http_code}" -X GET "${API_URL}$1" -H "Accept: application/json" -H "sid: ${SID}" ) # status are the last 3 characters status=$(printf %s "${response#"${response%???}"}") @@ -1284,8 +1315,6 @@ OutputJSON() { # Save current terminal settings (needed for later restore after password prompt) stty_orig=$(stty -g) - # Construct FTL's API address depending on the arguments supplied - ConstructAPI # Test if the authentication endpoint is available TestAPIAvailability # Authenticate with the FTL server @@ -1308,8 +1337,6 @@ ShowVersion() { # Save current terminal settings (needed for later restore after password prompt) stty_orig=$(stty -g) - # Construct FTL's API address depending on the arguments supplied - ConstructAPI # Test if the authentication endpoint is available TestAPIAvailability # Authenticate with the FTL server @@ -1585,9 +1612,7 @@ DisplayHelp() { ::: --xoff [num] set the x-offset, reference is the upper left corner, disables auto-centering ::: --yoff [num] set the y-offset, reference is the upper left corner, disables auto-centering ::: -::: --server url or address of your Pi-hole (default: 127.0.0.1) -::: --port port of your Pi-hole's API (default: 80) -::: --api path where your Pi-hole's API is hosted (default: api) +::: --server domain or IP of your Pi-hole (default: localhost) ::: --secret your Pi-hole's password, required to access the API ::: -j, --json output stats as JSON formatted string and exit and exit ::: -u, --update update to the latest version @@ -1666,8 +1691,6 @@ main(){ # Save current terminal settings (needed for later restore after password prompt) stty_orig=$(stty -g) - # Construct FTL's API address depending on the arguments supplied - ConstructAPI SizeChecker @@ -1686,9 +1709,7 @@ while [ "$#" -gt 0 ]; do "-v" | "--version" ) xOffset=0; ShowVersion; exit 0;; "--xoff" ) xOffset="$2"; xOffOrig="$2"; shift;; "--yoff" ) yOffset="$2"; yOffOrig="$2"; shift;; - "--server" ) URL="$2"; shift;; - "--port" ) PORT="$2"; shift;; - "--api" ) APIPATH="$2"; shift;; + "--server" ) SERVER="$2"; shift;; "--secret" ) password="$2"; shift;; * ) DisplayHelp; exit 1;; esac From 1b243f4a2d018150c977fa8800cd3fe28b7dd01c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sat, 2 Dec 2023 22:09:00 +0100 Subject: [PATCH 33/96] Adjust endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/padd.sh b/padd.sh index 3f7e9de..1034661 100755 --- a/padd.sh +++ b/padd.sh @@ -192,7 +192,7 @@ DeleteSession() { # SID is not null (successful authenthication only), delete the session if [ "${validSession}" = true ] && [ ! "${SID}" = null ]; then # Try to delete the session. Omit the output, but get the http status code - deleteResponse=$(curl -skS -o /dev/null -w "%{http_code}" -X DELETE "${API_URL}/auth" -H "Accept: application/json" -H "sid: ${SID}") + deleteResponse=$(curl -skS -o /dev/null -w "%{http_code}" -X DELETE "${API_URL}auth" -H "Accept: application/json" -H "sid: ${SID}") printf "\n\n" case "${deleteResponse}" in @@ -205,11 +205,11 @@ DeleteSession() { } LoginAPI() { - sessionResponse="$(curl -skS -X POST "${API_URL}/auth" --user-agent "PADD ${padd_version}" --data "{\"password\":\"${password}\"}" )" + sessionResponse="$(curl -skS -X POST "${API_URL}auth" --user-agent "PADD ${padd_version}" --data "{\"password\":\"${password}\"}" )" if [ -z "${sessionResponse}" ]; then moveXOffset; echo "No response from FTL server. Please check connectivity and use the options to set the API URL" - moveXOffset; echo "Usage: $0 [-u ] [-p ] [-a ] " + moveXOffset; echo "Usage: $0 [--server ]" exit 1 fi # obtain validity and session ID from session response @@ -242,10 +242,10 @@ GetFTLData() { ############################################# GETTERS ############################################## GetSummaryInformation() { - summary=$(GetFTLData "/stats/summary") - cache_info=$(GetFTLData "/info/metrics") - ftl_info=$(GetFTLData "/info/ftl") - dns_blocking=$(GetFTLData "/dns/blocking") + summary=$(GetFTLData "stats/summary") + cache_info=$(GetFTLData "info/metrics") + ftl_info=$(GetFTLData "info/ftl") + dns_blocking=$(GetFTLData "dns/blocking") clients=$(echo "${ftl_info}" | jq .ftl.clients.active 2>/dev/null) @@ -267,21 +267,21 @@ GetSummaryInformation() { cache_evictions=$(echo "$cache_info" | jq .metrics.dns.cache.evicted 2>/dev/null) cache_inserts=$(echo "$cache_info"| jq .metrics.dns.cache.inserted 2>/dev/null) - latest_blocked_raw=$(GetFTLData "/stats/recent_blocked?show=1" | jq --raw-output .blocked[0] 2>/dev/null) + latest_blocked_raw=$(GetFTLData "stats/recent_blocked?show=1" | jq --raw-output .blocked[0] 2>/dev/null) - top_blocked_raw=$(GetFTLData "/stats/top_domains?blocked=true" | jq --raw-output .domains[0].domain 2>/dev/null) + top_blocked_raw=$(GetFTLData "stats/top_domains?blocked=true" | jq --raw-output .domains[0].domain 2>/dev/null) - top_domain_raw=$(GetFTLData "/stats/top_domains" | jq --raw-output .domains[0].domain 2>/dev/null) + top_domain_raw=$(GetFTLData "stats/top_domains" | jq --raw-output .domains[0].domain 2>/dev/null) - top_client_raw=$(GetFTLData "/stats/top_clients" | jq --raw-output .clients[0].name 2>/dev/null) + top_client_raw=$(GetFTLData "stats/top_clients" | jq --raw-output .clients[0].name 2>/dev/null) if [ -z "${top_client_raw}" ]; then # if no hostname was supplied, use IP - top_client_raw=$(GetFTLData "/stats/top_clients" | jq --raw-output .clients[0].ip 2>/dev/null) + top_client_raw=$(GetFTLData "stats/top_clients" | jq --raw-output .clients[0].ip 2>/dev/null) fi } GetSystemInformation() { - sysinfo=$(GetFTLData "/info/system") + sysinfo=$(GetFTLData "info/system") # System uptime if [ "${sysinfo}" = 000 ]; then @@ -293,9 +293,9 @@ GetSystemInformation() { # CPU temperature and unit # in case .sensors.cpu_temp returns 'null' we substitute with 0 - cpu_temp_raw=$(GetFTLData "/info/sensors" | jq '(.sensors.cpu_temp // 0)' 2>/dev/null) + cpu_temp_raw=$(GetFTLData "info/sensors" | jq '(.sensors.cpu_temp // 0)' 2>/dev/null) cpu_temp=$(printf "%.1f" "${cpu_temp_raw}") - temp_unit=$(GetFTLData "/info/sensors" | jq --raw-output .sensors.unit 2>/dev/null) + temp_unit=$(GetFTLData "info/sensors" | jq --raw-output .sensors.unit 2>/dev/null) # Temp + Unit if [ "${temp_unit}" = "C" ]; then @@ -344,7 +344,7 @@ GetSystemInformation() { memory_heatmap="$(HeatmapGenerator "${memory_percent}")" # Get device model - sys_model="$(GetFTLData "/info/host" | jq --raw-output .host.model 2>/dev/null)" + sys_model="$(GetFTLData "info/host" | jq --raw-output .host.model 2>/dev/null)" # DOCKER_VERSION is set during GetVersionInformation, so this needs to run first during startup if [ ! "${DOCKER_VERSION}" = "null" ]; then @@ -361,8 +361,8 @@ GetSystemInformation() { } GetNetworkInformation() { - interfaces_raw=$(GetFTLData "/network/interfaces") - config=$(GetFTLData "/config") + interfaces_raw=$(GetFTLData "network/interfaces") + config=$(GetFTLData "config") # Get pi IPv4 address of the default interface pi_ip4_addrs="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv4[]' 2>/dev/null | wc -w)" @@ -421,7 +421,7 @@ GetNetworkInformation() { dhcp_heatmap=${red_text} dhcp_check_box=${check_box_bad} - GATEWAY="$(GetFTLData "/network/gateway" | jq --raw-output .address 2>/dev/null)" + GATEWAY="$(GetFTLData "network/gateway" | jq --raw-output .address 2>/dev/null)" dhcp_info=" Router: ${GATEWAY}" dhcp_ipv6_status="N/A" dhcp_ipv6_heatmap=${yellow_text} @@ -429,7 +429,7 @@ GetNetworkInformation() { fi # Get hostname - pi_hostname="$(GetFTLData "/info/host" | jq --raw-output .host.uname.nodename 2>/dev/null)" + pi_hostname="$(GetFTLData "info/host" | jq --raw-output .host.uname.nodename 2>/dev/null)" full_hostname=${pi_hostname} # when PI-hole is the DHCP server, append the domain to the hostname if [ "${DHCP_ACTIVE}" = "true" ]; then @@ -485,7 +485,7 @@ GetNetworkInformation() { } GetPiholeInformation() { - sysinfo=$(GetFTLData "/info/ftl") + sysinfo=$(GetFTLData "info/ftl") # If FTL is not running (sysinfo is 000), set all variables to "not running" connection_down_flag=false @@ -507,7 +507,7 @@ GetPiholeInformation() { ftl_cpu="$(printf "%.1f" "${ftl_cpu_raw}")%" ftl_mem_percentage="$(printf "%.1f" "${ftl_mem_percentage_raw}")%" # Get Pi-hole (blocking) status - ftl_dns_port=$(GetFTLData "/config" | jq .config.dns.port 2>/dev/null) + ftl_dns_port=$(GetFTLData "config" | jq .config.dns.port 2>/dev/null) # Get FTL's current PID ftlPID="$(echo "${sysinfo}" | jq .ftl.pid 2>/dev/null)" fi @@ -532,7 +532,7 @@ fi GetVersionInformation() { out_of_date_flag=false - versions_raw=$(GetFTLData "/info/version") + versions_raw=$(GetFTLData "info/version") # Gather DOCKER version information... # returns "null" if not running Pi-hole in Docker container @@ -1512,7 +1512,7 @@ NormalPADD() { # check if a new authentication is required (e.g. after connection to FTL has re-established) # GetFTLData() will return a 401 if a 401 http status code is returned # as $password should be set already, PADD should automatically re-authenticate - authenthication_required=$(GetFTLData "/info/ftl") + authenthication_required=$(GetFTLData "info/ftl") if [ "${authenthication_required}" = 401 ]; then LoginAPI fi From a41dcd0bb7365a0f007088246c0d604524cdc6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 5 Dec 2023 22:19:13 +0100 Subject: [PATCH 34/96] Cover --server localhost case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/padd.sh b/padd.sh index 1034661..5087792 100755 --- a/padd.sh +++ b/padd.sh @@ -107,7 +107,7 @@ TestAPIAvailability() { # Query the API URLs from FTL using CHAOS TXT # The result is a space-separated enumeration of full URLs # e.g., "http://localhost:80/api" or "https://domain.com:443/api" - if [ -z "${SERVER}" ]; then + if [ -z "${SERVER}" ] || [ "${SERVER}" = "localhost" ] || [ "${SERVER}" = "127.0.0.1" ]; then # --server was not set, assuming we're running locally chaos_api_list="$(dig +short chaos txt local.api.ftl @localhost)" else From 266a711e192f6b5eb0b783cf95984590d8096279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 5 Dec 2023 23:21:36 +0100 Subject: [PATCH 35/96] Improve error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/padd.sh b/padd.sh index 5087792..d629b78 100755 --- a/padd.sh +++ b/padd.sh @@ -102,23 +102,30 @@ padd_logo_retro_3="${bold_text}${green_text}| ${red_text}/${yellow_text}-${gre TestAPIAvailability() { - local chaos_api_list availabilityResonse + local chaos_api_list availabilityResonse cmdResult digReturnCode # Query the API URLs from FTL using CHAOS TXT # The result is a space-separated enumeration of full URLs # e.g., "http://localhost:80/api" or "https://domain.com:443/api" if [ -z "${SERVER}" ] || [ "${SERVER}" = "localhost" ] || [ "${SERVER}" = "127.0.0.1" ]; then - # --server was not set, assuming we're running locally - chaos_api_list="$(dig +short chaos txt local.api.ftl @localhost)" + # --server was not set or set to local, assuming we're running locally + cmdResult="$(dig +short chaos txt local.api.ftl @localhost 2>&1; echo $?)" else # --server was set, try to get response from there - chaos_api_list="$(dig +short chaos txt domain.api.ftl @"${SERVER}")" + cmdResult="$(dig +short chaos txt domain.api.ftl @"${SERVER}" 2>&1; echo $?)" fi - # If the query was not successful, the variable is empty - if [ -z "${chaos_api_list}" ]; then - echo "API not available. Please check connectivity" + # Gets the return code of the dig command (last line) + # We can't use${cmdResult##*$'\n'*} here as $'..' is not POSIX + digReturnCode="$(echo "${cmdResult}" | tail -n 1)" + + if [ ! "${digReturnCode}" = "0" ]; then + # If the query was not successful + echo "API not available. Please check server address and connectivity" exit 1 + else + # Dig returned 0 (success), so get the actual response (first line) + chaos_api_list="$(echo "${cmdResult}" | head -n 1)" fi # Iterate over space-separated list of URLs From 552ece2a963b1caf13f62a6732e791dc6dbe7365 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Dec 2023 10:35:15 +0000 Subject: [PATCH 36/96] Bump actions/stale from 8.0.0 to 9.0.0 Bumps [actions/stale](https://github.com/actions/stale) from 8.0.0 to 9.0.0. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v8.0.0...v9.0.0) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/stale.yml | 2 +- .github/workflows/stale_pr.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index f0b4085..a02ca80 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -17,7 +17,7 @@ jobs: issues: write steps: - - uses: actions/stale@v8.0.0 + - uses: actions/stale@v9.0.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} days-before-stale: 30 diff --git a/.github/workflows/stale_pr.yml b/.github/workflows/stale_pr.yml index 4a15110..171c903 100644 --- a/.github/workflows/stale_pr.yml +++ b/.github/workflows/stale_pr.yml @@ -17,7 +17,7 @@ jobs: pull-requests: write steps: - - uses: actions/stale@v8.0.0 + - uses: actions/stale@v9.0.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} # Do not automatically mark PR/issue as stale From 353c0035d08edb026b21de0b1ec4db9d1dec0827 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 7 Jan 2024 10:06:18 +0100 Subject: [PATCH 37/96] The correct key is config.dns.revServer.active Signed-off-by: DL6ER --- padd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/padd.sh b/padd.sh index 4d69719..d8aedf3 100755 --- a/padd.sh +++ b/padd.sh @@ -433,7 +433,7 @@ GetNetworkInformation() { fi # Conditional forwarding - CONDITIONAL_FORWARDING="$(echo "${config}" | jq .config.dns.rev_server.active 2>/dev/null)" + CONDITIONAL_FORWARDING="$(echo "${config}" | jq .config.dns.revServer.active 2>/dev/null)" if [ "${CONDITIONAL_FORWARDING}" = "true" ]; then conditional_forwarding_status="Enabled" conditional_forwarding_heatmap=${green_text} From 2455fff66f8855772e6219cacc4a4cfa9f5cb76e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sun, 7 Jan 2024 12:53:05 +0100 Subject: [PATCH 38/96] moveXOffset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/padd.sh b/padd.sh index d629b78..ecc9c8f 100755 --- a/padd.sh +++ b/padd.sh @@ -121,7 +121,7 @@ TestAPIAvailability() { if [ ! "${digReturnCode}" = "0" ]; then # If the query was not successful - echo "API not available. Please check server address and connectivity" + moveXOffset; echo "API not available. Please check server address and connectivity" exit 1 else # Dig returned 0 (success), so get the actual response (first line) @@ -162,8 +162,8 @@ TestAPIAvailability() { # if API_PORT is empty, no working API port was found if [ -n "${API_PORT}" ]; then - echo "API not available at: ${API_URL}" - echo "Exiting." + moveXOffset; echo "API not available at: ${API_URL}" + moveXOffset; echo "Exiting." exit 1 fi } From ec305e66076ed2b422b8f71992e37e8947130a20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sun, 7 Jan 2024 12:56:17 +0100 Subject: [PATCH 39/96] Return N/A in case FTL can't figure out the device model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/padd.sh b/padd.sh index ecc9c8f..5da4c0a 100755 --- a/padd.sh +++ b/padd.sh @@ -362,8 +362,9 @@ GetSystemInformation() { # Cleaning device model from useless OEM information sys_model=$(filterModel "${sys_model}") - if [ -z "$sys_model" ]; then - sys_model="Unknown" + # FTL returns null if device information is not available + if [ -z "$sys_model" ] || [ "$sys_model" = "null" ]; then + sys_model="N/A" fi } From ec5a26a705985bf754418573634b4d3b6927e403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sun, 7 Jan 2024 13:32:09 +0100 Subject: [PATCH 40/96] Deleting a session successfully returns 204 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/padd.sh b/padd.sh index d8aedf3..cf8c1e8 100755 --- a/padd.sh +++ b/padd.sh @@ -166,8 +166,8 @@ DeleteSession() { printf "\n\n" case "${deleteResponse}" in "200") moveXOffset; printf "%b" "A session that was not created cannot be deleted (e.g., empty API password).\n";; + "204") moveXOffset; printf "%b" "Session successfully deleted.\n";; "401") moveXOffset; printf "%b" "Logout attempt without a valid session. Unauthorized!\n";; - "410") moveXOffset; printf "%b" "Session successfully deleted.\n";; esac; fi @@ -1353,7 +1353,7 @@ StartupRoutine(){ moveXOffset; printf "%b" "Establishing connection with FTL...\n" Authenthication - printf "%b" "Starting PADD...\n" + moveXOffset; printf "%b" "Starting PADD...\n" moveXOffset; printf "%b" " [■·········] 10%\r" From 79ca42e2e7f7529a48ac90afdcba8f58daeb3f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sun, 7 Jan 2024 21:05:49 +0100 Subject: [PATCH 41/96] Status 200 is gone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/padd.sh b/padd.sh index cf8c1e8..49d5801 100755 --- a/padd.sh +++ b/padd.sh @@ -165,7 +165,6 @@ DeleteSession() { printf "\n\n" case "${deleteResponse}" in - "200") moveXOffset; printf "%b" "A session that was not created cannot be deleted (e.g., empty API password).\n";; "204") moveXOffset; printf "%b" "Session successfully deleted.\n";; "401") moveXOffset; printf "%b" "Logout attempt without a valid session. Unauthorized!\n";; esac; From d58149d5fa744515e72b235d8a5600648a76faa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sun, 7 Jan 2024 22:03:54 +0100 Subject: [PATCH 42/96] Nicer output if no session needed to be deleted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- padd.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/padd.sh b/padd.sh index 49d5801..1d20cdc 100755 --- a/padd.sh +++ b/padd.sh @@ -168,6 +168,9 @@ DeleteSession() { "204") moveXOffset; printf "%b" "Session successfully deleted.\n";; "401") moveXOffset; printf "%b" "Logout attempt without a valid session. Unauthorized!\n";; esac; + else + # no session to delete, just print a newline for nicer output + echo fi } From 5f8d24fb2495d2515a3d492703bad09335797012 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 30 Mar 2024 10:10:21 +0000 Subject: [PATCH 43/96] Bump eps1lon/actions-label-merge-conflict from 2.1.0 to 3.0.0 Bumps [eps1lon/actions-label-merge-conflict](https://github.com/eps1lon/actions-label-merge-conflict) from 2.1.0 to 3.0.0. - [Release notes](https://github.com/eps1lon/actions-label-merge-conflict/releases) - [Changelog](https://github.com/eps1lon/actions-label-merge-conflict/blob/main/CHANGELOG.md) - [Commits](https://github.com/eps1lon/actions-label-merge-conflict/compare/v2.1.0...v3.0.0) --- updated-dependencies: - dependency-name: eps1lon/actions-label-merge-conflict dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/merge-conflict.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/merge-conflict.yml b/.github/workflows/merge-conflict.yml index 424a1c0..89b0398 100644 --- a/.github/workflows/merge-conflict.yml +++ b/.github/workflows/merge-conflict.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check if PRs are have merge conflicts - uses: eps1lon/actions-label-merge-conflict@v2.1.0 + uses: eps1lon/actions-label-merge-conflict@v3.0.0 with: dirtyLabel: "Merge Conflict" repoToken: "${{ secrets.GITHUB_TOKEN }}" From 06c76ff746b5e307c6cb0bdc5d5e80351aa9c2d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 20 Apr 2024 10:31:36 +0000 Subject: [PATCH 44/96] Bump actions/checkout from 4.1.1 to 4.1.3 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.1 to 4.1.3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.1.1...v4.1.3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codespell.yml | 2 +- .github/workflows/editorconfig-checker.yml | 2 +- .github/workflows/stale.yml | 2 +- .github/workflows/sync-back-to-dev.yml | 2 +- .github/workflows/version_bump.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index cbd7f85..e2f19e2 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.3 - name: Spell-Checking uses: codespell-project/actions-codespell@master diff --git a/.github/workflows/editorconfig-checker.yml b/.github/workflows/editorconfig-checker.yml index 807dc02..6d3237f 100644 --- a/.github/workflows/editorconfig-checker.yml +++ b/.github/workflows/editorconfig-checker.yml @@ -9,6 +9,6 @@ jobs: name: editorconfig-checker runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.1 + - uses: actions/checkout@v4.1.3 - uses: editorconfig-checker/action-editorconfig-checker@main # current tag v1.0.0 is really out-of-date - run: editorconfig-checker diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index a02ca80..d926fd0 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.3 - name: Remove 'stale' label run: gh issue edit ${{ github.event.issue.number }} --remove-label ${{ env.stale_label }} env: diff --git a/.github/workflows/sync-back-to-dev.yml b/.github/workflows/sync-back-to-dev.yml index 3d8b7c5..1d740fb 100644 --- a/.github/workflows/sync-back-to-dev.yml +++ b/.github/workflows/sync-back-to-dev.yml @@ -11,7 +11,7 @@ jobs: name: Syncing branches steps: - name: Checkout - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.3 - name: Opening pull request run: gh pr create -B development -H master --title 'Sync master back into development' --body 'Created by Github action' --label 'Internal' env: diff --git a/.github/workflows/version_bump.yml b/.github/workflows/version_bump.yml index e0f95ee..75d60ba 100644 --- a/.github/workflows/version_bump.yml +++ b/.github/workflows/version_bump.yml @@ -19,7 +19,7 @@ jobs: echo "latest_tag=$LATEST_TAG" >> $GITHUB_ENV - name: Checkout code - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.3 with: ref: 'development' From ae766fb76ef9906cd984d2f4c9c540b1317d64bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 27 Apr 2024 10:37:34 +0000 Subject: [PATCH 45/96] Bump actions/checkout from 4.1.3 to 4.1.4 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.3 to 4.1.4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.1.3...v4.1.4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codespell.yml | 2 +- .github/workflows/editorconfig-checker.yml | 2 +- .github/workflows/stale.yml | 2 +- .github/workflows/sync-back-to-dev.yml | 2 +- .github/workflows/version_bump.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index e2f19e2..5f3a9ad 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.1.3 + uses: actions/checkout@v4.1.4 - name: Spell-Checking uses: codespell-project/actions-codespell@master diff --git a/.github/workflows/editorconfig-checker.yml b/.github/workflows/editorconfig-checker.yml index 6d3237f..161e8a5 100644 --- a/.github/workflows/editorconfig-checker.yml +++ b/.github/workflows/editorconfig-checker.yml @@ -9,6 +9,6 @@ jobs: name: editorconfig-checker runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.3 + - uses: actions/checkout@v4.1.4 - uses: editorconfig-checker/action-editorconfig-checker@main # current tag v1.0.0 is really out-of-date - run: editorconfig-checker diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index d926fd0..bfab06d 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4.1.3 + uses: actions/checkout@v4.1.4 - name: Remove 'stale' label run: gh issue edit ${{ github.event.issue.number }} --remove-label ${{ env.stale_label }} env: diff --git a/.github/workflows/sync-back-to-dev.yml b/.github/workflows/sync-back-to-dev.yml index 1d740fb..2e1be7c 100644 --- a/.github/workflows/sync-back-to-dev.yml +++ b/.github/workflows/sync-back-to-dev.yml @@ -11,7 +11,7 @@ jobs: name: Syncing branches steps: - name: Checkout - uses: actions/checkout@v4.1.3 + uses: actions/checkout@v4.1.4 - name: Opening pull request run: gh pr create -B development -H master --title 'Sync master back into development' --body 'Created by Github action' --label 'Internal' env: diff --git a/.github/workflows/version_bump.yml b/.github/workflows/version_bump.yml index 75d60ba..44f6ef1 100644 --- a/.github/workflows/version_bump.yml +++ b/.github/workflows/version_bump.yml @@ -19,7 +19,7 @@ jobs: echo "latest_tag=$LATEST_TAG" >> $GITHUB_ENV - name: Checkout code - uses: actions/checkout@v4.1.3 + uses: actions/checkout@v4.1.4 with: ref: 'development' From b950a9947e12ae80c6ee9c4733edd6a58e4461c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 May 2024 10:38:30 +0000 Subject: [PATCH 46/96] Bump eps1lon/actions-label-merge-conflict from 3.0.0 to 3.0.1 Bumps [eps1lon/actions-label-merge-conflict](https://github.com/eps1lon/actions-label-merge-conflict) from 3.0.0 to 3.0.1. - [Release notes](https://github.com/eps1lon/actions-label-merge-conflict/releases) - [Changelog](https://github.com/eps1lon/actions-label-merge-conflict/blob/main/CHANGELOG.md) - [Commits](https://github.com/eps1lon/actions-label-merge-conflict/compare/v3.0.0...v3.0.1) --- updated-dependencies: - dependency-name: eps1lon/actions-label-merge-conflict dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/merge-conflict.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/merge-conflict.yml b/.github/workflows/merge-conflict.yml index 89b0398..857aef0 100644 --- a/.github/workflows/merge-conflict.yml +++ b/.github/workflows/merge-conflict.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check if PRs are have merge conflicts - uses: eps1lon/actions-label-merge-conflict@v3.0.0 + uses: eps1lon/actions-label-merge-conflict@v3.0.1 with: dirtyLabel: "Merge Conflict" repoToken: "${{ secrets.GITHUB_TOKEN }}" From 29ce0396cedc591da011d6c4dbc3ddfe0e575436 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 May 2024 12:24:34 +0000 Subject: [PATCH 47/96] Bump actions/checkout from 4.1.4 to 4.1.5 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.4 to 4.1.5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.1.4...v4.1.5) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codespell.yml | 2 +- .github/workflows/editorconfig-checker.yml | 2 +- .github/workflows/stale.yml | 2 +- .github/workflows/sync-back-to-dev.yml | 2 +- .github/workflows/version_bump.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 5f3a9ad..f6874d4 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.1.4 + uses: actions/checkout@v4.1.5 - name: Spell-Checking uses: codespell-project/actions-codespell@master diff --git a/.github/workflows/editorconfig-checker.yml b/.github/workflows/editorconfig-checker.yml index 161e8a5..8b61279 100644 --- a/.github/workflows/editorconfig-checker.yml +++ b/.github/workflows/editorconfig-checker.yml @@ -9,6 +9,6 @@ jobs: name: editorconfig-checker runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.4 + - uses: actions/checkout@v4.1.5 - uses: editorconfig-checker/action-editorconfig-checker@main # current tag v1.0.0 is really out-of-date - run: editorconfig-checker diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index bfab06d..d689d63 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4.1.4 + uses: actions/checkout@v4.1.5 - name: Remove 'stale' label run: gh issue edit ${{ github.event.issue.number }} --remove-label ${{ env.stale_label }} env: diff --git a/.github/workflows/sync-back-to-dev.yml b/.github/workflows/sync-back-to-dev.yml index 2e1be7c..7cc1180 100644 --- a/.github/workflows/sync-back-to-dev.yml +++ b/.github/workflows/sync-back-to-dev.yml @@ -11,7 +11,7 @@ jobs: name: Syncing branches steps: - name: Checkout - uses: actions/checkout@v4.1.4 + uses: actions/checkout@v4.1.5 - name: Opening pull request run: gh pr create -B development -H master --title 'Sync master back into development' --body 'Created by Github action' --label 'Internal' env: diff --git a/.github/workflows/version_bump.yml b/.github/workflows/version_bump.yml index 44f6ef1..92dc59c 100644 --- a/.github/workflows/version_bump.yml +++ b/.github/workflows/version_bump.yml @@ -19,7 +19,7 @@ jobs: echo "latest_tag=$LATEST_TAG" >> $GITHUB_ENV - name: Checkout code - uses: actions/checkout@v4.1.4 + uses: actions/checkout@v4.1.5 with: ref: 'development' From d627197780ec8f8cb9fa87f4be84ed71f864bb5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 18 May 2024 10:45:43 +0000 Subject: [PATCH 48/96] Bump actions/checkout from 4.1.5 to 4.1.6 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.5 to 4.1.6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.1.5...v4.1.6) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codespell.yml | 2 +- .github/workflows/editorconfig-checker.yml | 2 +- .github/workflows/stale.yml | 2 +- .github/workflows/sync-back-to-dev.yml | 2 +- .github/workflows/version_bump.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index f6874d4..a7c7604 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Spell-Checking uses: codespell-project/actions-codespell@master diff --git a/.github/workflows/editorconfig-checker.yml b/.github/workflows/editorconfig-checker.yml index 8b61279..e6b2821 100644 --- a/.github/workflows/editorconfig-checker.yml +++ b/.github/workflows/editorconfig-checker.yml @@ -9,6 +9,6 @@ jobs: name: editorconfig-checker runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.5 + - uses: actions/checkout@v4.1.6 - uses: editorconfig-checker/action-editorconfig-checker@main # current tag v1.0.0 is really out-of-date - run: editorconfig-checker diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index d689d63..ae034ef 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Remove 'stale' label run: gh issue edit ${{ github.event.issue.number }} --remove-label ${{ env.stale_label }} env: diff --git a/.github/workflows/sync-back-to-dev.yml b/.github/workflows/sync-back-to-dev.yml index 7cc1180..7e0c90c 100644 --- a/.github/workflows/sync-back-to-dev.yml +++ b/.github/workflows/sync-back-to-dev.yml @@ -11,7 +11,7 @@ jobs: name: Syncing branches steps: - name: Checkout - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 - name: Opening pull request run: gh pr create -B development -H master --title 'Sync master back into development' --body 'Created by Github action' --label 'Internal' env: diff --git a/.github/workflows/version_bump.yml b/.github/workflows/version_bump.yml index 92dc59c..94e0047 100644 --- a/.github/workflows/version_bump.yml +++ b/.github/workflows/version_bump.yml @@ -19,7 +19,7 @@ jobs: echo "latest_tag=$LATEST_TAG" >> $GITHUB_ENV - name: Checkout code - uses: actions/checkout@v4.1.5 + uses: actions/checkout@v4.1.6 with: ref: 'development' From ebfaf8ef0c777915af23cead6f60f832db5f217b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jun 2024 10:56:23 +0000 Subject: [PATCH 49/96] Bump eps1lon/actions-label-merge-conflict from 3.0.1 to 3.0.2 Bumps [eps1lon/actions-label-merge-conflict](https://github.com/eps1lon/actions-label-merge-conflict) from 3.0.1 to 3.0.2. - [Release notes](https://github.com/eps1lon/actions-label-merge-conflict/releases) - [Changelog](https://github.com/eps1lon/actions-label-merge-conflict/blob/main/CHANGELOG.md) - [Commits](https://github.com/eps1lon/actions-label-merge-conflict/compare/v3.0.1...v3.0.2) --- updated-dependencies: - dependency-name: eps1lon/actions-label-merge-conflict dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/merge-conflict.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/merge-conflict.yml b/.github/workflows/merge-conflict.yml index 857aef0..c24de2c 100644 --- a/.github/workflows/merge-conflict.yml +++ b/.github/workflows/merge-conflict.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check if PRs are have merge conflicts - uses: eps1lon/actions-label-merge-conflict@v3.0.1 + uses: eps1lon/actions-label-merge-conflict@v3.0.2 with: dirtyLabel: "Merge Conflict" repoToken: "${{ secrets.GITHUB_TOKEN }}" From b5bfe71bdbc554df3ebbd14b9f9dfe9a4faf6d6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 15 Jun 2024 10:10:20 +0000 Subject: [PATCH 50/96] Bump actions/checkout from 4.1.6 to 4.1.7 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.6 to 4.1.7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.1.6...v4.1.7) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codespell.yml | 2 +- .github/workflows/editorconfig-checker.yml | 2 +- .github/workflows/stale.yml | 2 +- .github/workflows/sync-back-to-dev.yml | 2 +- .github/workflows/version_bump.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index a7c7604..693eda0 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Spell-Checking uses: codespell-project/actions-codespell@master diff --git a/.github/workflows/editorconfig-checker.yml b/.github/workflows/editorconfig-checker.yml index e6b2821..5cd18d4 100644 --- a/.github/workflows/editorconfig-checker.yml +++ b/.github/workflows/editorconfig-checker.yml @@ -9,6 +9,6 @@ jobs: name: editorconfig-checker runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.6 + - uses: actions/checkout@v4.1.7 - uses: editorconfig-checker/action-editorconfig-checker@main # current tag v1.0.0 is really out-of-date - run: editorconfig-checker diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index ae034ef..6f93787 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Remove 'stale' label run: gh issue edit ${{ github.event.issue.number }} --remove-label ${{ env.stale_label }} env: diff --git a/.github/workflows/sync-back-to-dev.yml b/.github/workflows/sync-back-to-dev.yml index 7e0c90c..db88f65 100644 --- a/.github/workflows/sync-back-to-dev.yml +++ b/.github/workflows/sync-back-to-dev.yml @@ -11,7 +11,7 @@ jobs: name: Syncing branches steps: - name: Checkout - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 - name: Opening pull request run: gh pr create -B development -H master --title 'Sync master back into development' --body 'Created by Github action' --label 'Internal' env: diff --git a/.github/workflows/version_bump.yml b/.github/workflows/version_bump.yml index 94e0047..5801f8d 100644 --- a/.github/workflows/version_bump.yml +++ b/.github/workflows/version_bump.yml @@ -19,7 +19,7 @@ jobs: echo "latest_tag=$LATEST_TAG" >> $GITHUB_ENV - name: Checkout code - uses: actions/checkout@v4.1.6 + uses: actions/checkout@v4.1.7 with: ref: 'development' From 8b8e2194487ac94c774b29d0ae19923d36cab10f Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 19 Jun 2024 22:31:12 +0200 Subject: [PATCH 51/96] Rename API functions for consistency with core code Signed-off-by: DL6ER --- padd.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/padd.sh b/padd.sh index 0eeff12..67ef636 100755 --- a/padd.sh +++ b/padd.sh @@ -168,9 +168,9 @@ TestAPIAvailability() { fi } -Authenthication() { +LoginAPI() { # Try to authenticate - LoginAPI + Authenticate while [ "${validSession}" = false ] || [ -z "${validSession}" ] ; do moveXOffset; echo "Authentication failed." @@ -186,7 +186,7 @@ Authenthication() { moveXOffset; secretRead; printf '\n' # Try to authenticate again - LoginAPI + Authenticate done # Loop exited, authentication was successful @@ -213,7 +213,7 @@ DeleteSession() { } -LoginAPI() { +Authenticate() { sessionResponse="$(curl -skS -X POST "${API_URL}auth" --user-agent "PADD ${padd_version}" --data "{\"password\":\"${password}\"}" )" if [ -z "${sessionResponse}" ]; then @@ -1329,7 +1329,7 @@ OutputJSON() { TestAPIAvailability # Authenticate with the FTL server printf "%b" "Establishing connection with FTL...\n" - Authenthication + LoginAPI GetSummaryInformation printf "%b" "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today},\"clients\": ${clients}}" @@ -1351,7 +1351,7 @@ ShowVersion() { TestAPIAvailability # Authenticate with the FTL server printf "%b" "Establishing connection with FTL...\n" - Authenthication + LoginAPI GetVersionInformation GetPADDInformation @@ -1388,7 +1388,7 @@ StartupRoutine(){ # Authenticate with the FTL server moveXOffset; printf "%b" "Establishing connection with FTL...\n" - Authenthication + LoginAPI moveXOffset; printf "%b" "Starting PADD...\n" @@ -1420,7 +1420,7 @@ StartupRoutine(){ TestAPIAvailability # Authenticate with the FTL server moveXOffset; printf "%b" "Establishing connection with FTL...\n" - Authenthication + LoginAPI # Get our information for the first time moveXOffset; echo "- Gathering version info." @@ -1455,7 +1455,7 @@ StartupRoutine(){ # Authenticate with the FTL server moveXOffset; printf "%b" "Establishing connection with FTL...\n" - Authenthication + LoginAPI # Get our information for the first time @@ -1524,7 +1524,7 @@ NormalPADD() { # as $password should be set already, PADD should automatically re-authenticate authenthication_required=$(GetFTLData "info/ftl") if [ "${authenthication_required}" = 401 ]; then - LoginAPI + Authenticate fi # Get uptime, CPU load, temp, etc. every 5 seconds From 8316033d4db6d708bf9a2c4a12472e6f80aee1cc Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 19 Jun 2024 22:31:58 +0200 Subject: [PATCH 52/96] Try to use the CLI password for logins (if enabled and readable by the current user) Signed-off-by: DL6ER --- padd.sh | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/padd.sh b/padd.sh index 67ef636..efbcbe1 100755 --- a/padd.sh +++ b/padd.sh @@ -145,6 +145,12 @@ TestAPIAvailability() { API_PORT="" else # API is available at this URL combination + + if [ "${availabilityResonse}" = 200 ]; then + # API is available without authentication + needAuth=false + fi + break fi @@ -169,9 +175,21 @@ TestAPIAvailability() { } LoginAPI() { - # Try to authenticate - Authenticate + # Exit early if no authentication is required + if [ "${needAuth}" = false ]; then + moveXOffset; echo "No password required." + return + fi + # Try to read the CLI password (if enabled and readable by the current user) + if [ -r /etc/pihole/cli_pw ]; then + password=$(cat /etc/pihole/cli_pw) + + # Try to authenticate using the CLI password + Authenticate + fi + + # If this did not work, ask the user for the password while [ "${validSession}" = false ] || [ -z "${validSession}" ] ; do moveXOffset; echo "Authentication failed." From 770ce440fa9db46b60b77a80b738718529132630 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 22 Jun 2024 20:52:18 +0200 Subject: [PATCH 53/96] Fix old spelling issue Signed-off-by: DL6ER --- padd.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/padd.sh b/padd.sh index efbcbe1..ea792ef 100755 --- a/padd.sh +++ b/padd.sh @@ -102,7 +102,7 @@ padd_logo_retro_3="${bold_text}${green_text}| ${red_text}/${yellow_text}-${gre TestAPIAvailability() { - local chaos_api_list availabilityResonse cmdResult digReturnCode + local chaos_api_list availabilityResponse cmdResult digReturnCode # Query the API URLs from FTL using CHAOS TXT # The result is a space-separated enumeration of full URLs @@ -137,16 +137,16 @@ TestAPIAvailability() { API_URL="${API_URL#\"}" # Test if the API is available at this URL - availabilityResonse=$(curl -skS -o /dev/null -w "%{http_code}" "${API_URL}auth") + availabilityResponse=$(curl -skS -o /dev/null -w "%{http_code}" "${API_URL}auth") # Test if http status code was 200 (OK) or 401 (authentication required) - if [ ! "${availabilityResonse}" = 200 ] && [ ! "${availabilityResonse}" = 401 ]; then + if [ ! "${availabilityResponse}" = 200 ] && [ ! "${availabilityResponse}" = 401 ]; then # API is not available at this port/protocol combination API_PORT="" else # API is available at this URL combination - if [ "${availabilityResonse}" = 200 ]; then + if [ "${availabilityResponse}" = 200 ]; then # API is available without authentication needAuth=false fi From 7f3d46f5a684008a769b9b970171125b3cc1fcc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 3 Jul 2024 19:45:13 +0200 Subject: [PATCH 54/96] Exit bump workflow early if latest tag is empty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König --- .github/workflows/version_bump.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/version_bump.yml b/.github/workflows/version_bump.yml index 5801f8d..14c6e83 100644 --- a/.github/workflows/version_bump.yml +++ b/.github/workflows/version_bump.yml @@ -17,6 +17,7 @@ jobs: LATEST_TAG=$(gh -R $REPO release list -L 1 | awk '{printf $3}') echo "Latest version tag for releases in $REPO is $LATEST_TAG" echo "latest_tag=$LATEST_TAG" >> $GITHUB_ENV + [[ -z ${LATEST_TAG} ]] && echo "Error: LATEST_TAG is empty, aborting" && exit 1 - name: Checkout code uses: actions/checkout@v4.1.7 From 11723bce9704b8f4c4a36e6876262bc5330abbb8 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 14 Jul 2024 15:09:49 +0200 Subject: [PATCH 55/96] Modify PADD to comply with the changes in FTL on the same branch Signed-off-by: DL6ER --- padd.sh | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/padd.sh b/padd.sh index ea792ef..f66583d 100755 --- a/padd.sh +++ b/padd.sh @@ -390,34 +390,39 @@ GetSystemInformation() { GetNetworkInformation() { interfaces_raw=$(GetFTLData "network/interfaces") + gateway_raw=$(GetFTLData "network/gateway") + gateway_v4_iface=$(echo "${gateway_raw}" | jq -r '.gateway[] | select(.family == "inet") | .interface' | head -n 1) + v4_iface_data=$(echo "${interfaces_raw}" | jq --arg iface "${gateway_v4_iface}" '.interfaces[] | select(.name==$iface)' 2>/dev/null) + gateway_v6_iface=$(echo "${gateway_raw}" | jq -r '.gateway[] | select(.family == "inet6") | .interface' | head -n 1) + v6_iface_data=$(echo "${interfaces_raw}" | jq --arg iface "${gateway_v6_iface}" '.interfaces[] | select(.name==$iface)' 2>/dev/null) config=$(GetFTLData "config") # Get pi IPv4 address of the default interface - pi_ip4_addrs="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv4[]' 2>/dev/null | wc -w)" - if [ "${pi_ip4_addrs}" -eq 0 ]; then + pi_ip4_addrs="$(echo "${v4_iface_data}" | jq --raw-output '.addresses[] | select(.family=="inet") | .address' 2>/dev/null)" + if [ $(echo "${pi_ip4_addrs}" | wc -l) -eq 0 ]; then # No IPv4 address available pi_ip4_addr="N/A" - elif [ "${pi_ip4_addrs}" -eq 1 ]; then + elif [ $(echo "${pi_ip4_addrs}" | wc -l) -eq 1 ]; then # One IPv4 address available - pi_ip4_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv4[0]' 2>/dev/null)" + pi_ip4_addr=${pi_ip4_addrs} else # More than one IPv4 address available - pi_ip4_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv4[0]' 2>/dev/null)+" + pi_ip4_addr="$(echo "${pi_ip4_addrs}" | head -n 1)+" fi # Get pi IPv6 address of the default interface - pi_ip6_addrs="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv6[]' 2>/dev/null | wc -w)" - if [ "${pi_ip6_addrs}" -eq 0 ]; then + pi_ip6_addrs="$(echo "${v6_iface_data}" | jq --raw-output '.addresses[] | select(.family=="inet6") | .address' 2>/dev/null)" + if [ $(echo "${pi_ip6_addrs}" | wc -l) -eq 0 ]; then # No IPv6 address available pi_ip6_addr="N/A" ipv6_check_box=${check_box_bad} - elif [ "${pi_ip6_addrs}" -eq 1 ]; then + elif [ $(echo "${pi_ip6_addrs}" | wc -l) -eq 1 ]; then # One IPv6 address available - pi_ip6_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv6[0]' 2>/dev/null | cut -f1 -d "%" )" + pi_ip6_addr=${pi_ip6_addrs} ipv6_check_box=${check_box_good} else # More than one IPv6 address available - pi_ip6_addr="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .ipv6[0]' 2>/dev/null | cut -f1 -d "%" )+" + pi_ip6_addr="$(echo "${pi_ip6_addrs}" | head -n 1)+" ipv6_check_box=${check_box_good} fi @@ -449,7 +454,8 @@ GetNetworkInformation() { dhcp_heatmap=${red_text} dhcp_check_box=${check_box_bad} - GATEWAY="$(GetFTLData "network/gateway" | jq --raw-output .address 2>/dev/null)" + # Display the gateway address if DHCP is disabled + GATEWAY="$(echo "${gateway_raw}" | jq -r '.gateway[] | select(.family == "inet") | .address' | head -n 1)" dhcp_info=" Router: ${GATEWAY}" dhcp_ipv6_status="N/A" dhcp_ipv6_heatmap=${yellow_text} @@ -501,15 +507,23 @@ GetNetworkInformation() { conditional_forwarding_heatmap=${red_text} fi - # Default interface data - iface_name="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .name' 2>/dev/null)" - tx_bytes="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .tx.num' 2>/dev/null)" - tx_bytes_unit="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .tx.unit' 2>/dev/null)" + # Default interface data (use IPv4 interface - we cannot show both and assume they are the same) + iface_name="${gateway_v4_iface}" + tx_bytes="$(echo "${v4_iface_data}" | jq --raw-output '.stats.tx_bytes.value' 2>/dev/null)" + tx_bytes_unit="$(echo "${v4_iface_data}" | jq --raw-output '.stats.tx_bytes.unit' 2>/dev/null)" tx_bytes=$(printf "%.1f %b" "${tx_bytes}" "${tx_bytes_unit}") - rx_bytes="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .rx.num' 2>/dev/null)" - rx_bytes_unit="$(echo "${interfaces_raw}" | jq --raw-output '.interfaces[] | select(.default==true) | .rx.unit' 2>/dev/null)" + rx_bytes="$(echo "${v4_iface_data}" | jq --raw-output '.stats.rx_bytes.value' 2>/dev/null)" + rx_bytes_unit="$(echo "${v4_iface_data}" | jq --raw-output '.stats.rx_bytes.unit' 2>/dev/null)" rx_bytes=$(printf "%.1f %b" "${rx_bytes}" "${rx_bytes_unit}") + + # If IPv4 and IPv6 interfaces are not the same, add a "*" to the interface + # name to highlight that there are two different interfaces and the + # displayed statistics are only for the IPv4 interface, while the IPv6 + # address correctly corresponds to the default IPv6 interface + if [ ! "${gateway_v4_iface}" = "${gateway_v6_iface}" ]; then + iface_name="${iface_name}*" + fi } GetPiholeInformation() { From c7f7608659618d3973c593c0e59337ebaca94d90 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 14 Jul 2024 16:45:24 +0200 Subject: [PATCH 56/96] Fix editorconfig errors even if not introduced by the PR at hand Signed-off-by: DL6ER --- padd.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/padd.sh b/padd.sh index f66583d..3790471 100755 --- a/padd.sh +++ b/padd.sh @@ -232,22 +232,22 @@ DeleteSession() { } Authenticate() { - sessionResponse="$(curl -skS -X POST "${API_URL}auth" --user-agent "PADD ${padd_version}" --data "{\"password\":\"${password}\"}" )" + sessionResponse="$(curl -skS -X POST "${API_URL}auth" --user-agent "PADD ${padd_version}" --data "{\"password\":\"${password}\"}" )" if [ -z "${sessionResponse}" ]; then moveXOffset; echo "No response from FTL server. Please check connectivity and use the options to set the API URL" moveXOffset; echo "Usage: $0 [--server ]" exit 1 fi - # obtain validity and session ID from session response - validSession=$(echo "${sessionResponse}"| jq .session.valid 2>/dev/null) - SID=$(echo "${sessionResponse}"| jq --raw-output .session.sid 2>/dev/null) + # obtain validity and session ID from session response + validSession=$(echo "${sessionResponse}"| jq .session.valid 2>/dev/null) + SID=$(echo "${sessionResponse}"| jq --raw-output .session.sid 2>/dev/null) } GetFTLData() { local response # get the data from querying the API as well as the http status code - response=$(curl -skS -w "%{http_code}" -X GET "${API_URL}$1" -H "Accept: application/json" -H "sid: ${SID}" ) + response=$(curl -skS -w "%{http_code}" -X GET "${API_URL}$1" -H "Accept: application/json" -H "sid: ${SID}" ) # status are the last 3 characters status=$(printf %s "${response#"${response%???}"}") From c1adc4a6eb977eb5532e29778771503a43f947d2 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Sun, 14 Jul 2024 21:42:10 +0200 Subject: [PATCH 57/96] DHCP is a top level config object Signed-off-by: yubiuser --- padd.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/padd.sh b/padd.sh index ea792ef..105cae9 100755 --- a/padd.sh +++ b/padd.sh @@ -422,11 +422,11 @@ GetNetworkInformation() { fi # Is Pi-Hole acting as the DHCP server? - DHCP_ACTIVE="$(echo "${config}" | jq .config.dns.dhcp.active 2>/dev/null )" + DHCP_ACTIVE="$(echo "${config}" | jq .config.dhcp.active 2>/dev/null )" if [ "${DHCP_ACTIVE}" = "true" ]; then - DHCP_START="$(echo "${config}" | jq --raw-output .config.dns.dhcp.start 2>/dev/null)" - DHCP_END="$(echo "${config}" | jq --raw-output .config.dns.dhcp.end 2>/dev/null)" + DHCP_START="$(echo "${config}" | jq --raw-output .config.dhcp.start 2>/dev/null)" + DHCP_END="$(echo "${config}" | jq --raw-output .config.dhcp.end 2>/dev/null)" dhcp_status="Enabled" dhcp_info=" Range: ${DHCP_START} - ${DHCP_END}" @@ -434,7 +434,7 @@ GetNetworkInformation() { dhcp_check_box=${check_box_good} # Is DHCP handling IPv6? - DHCP_IPv6="$(echo "${config}" | jq --raw-output .config.dns.dhcp.ipv6 2>/dev/null)" + DHCP_IPv6="$(echo "${config}" | jq --raw-output .config.dhcp.ipv6 2>/dev/null)" if [ "${DHCP_IPv6}" = "true" ]; then dhcp_ipv6_status="Enabled" dhcp_ipv6_heatmap=${green_text} From 19808bfb577e1209fa8f4890b32fd404d4de85e3 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Sun, 14 Jul 2024 21:53:28 +0200 Subject: [PATCH 58/96] Fix idention style Signed-off-by: yubiuser --- padd.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/padd.sh b/padd.sh index 105cae9..d54f02a 100755 --- a/padd.sh +++ b/padd.sh @@ -232,22 +232,22 @@ DeleteSession() { } Authenticate() { - sessionResponse="$(curl -skS -X POST "${API_URL}auth" --user-agent "PADD ${padd_version}" --data "{\"password\":\"${password}\"}" )" + sessionResponse="$(curl -skS -X POST "${API_URL}auth" --user-agent "PADD ${padd_version}" --data "{\"password\":\"${password}\"}" )" if [ -z "${sessionResponse}" ]; then moveXOffset; echo "No response from FTL server. Please check connectivity and use the options to set the API URL" moveXOffset; echo "Usage: $0 [--server ]" exit 1 fi - # obtain validity and session ID from session response - validSession=$(echo "${sessionResponse}"| jq .session.valid 2>/dev/null) - SID=$(echo "${sessionResponse}"| jq --raw-output .session.sid 2>/dev/null) + # obtain validity and session ID from session response + validSession=$(echo "${sessionResponse}"| jq .session.valid 2>/dev/null) + SID=$(echo "${sessionResponse}"| jq --raw-output .session.sid 2>/dev/null) } GetFTLData() { local response # get the data from querying the API as well as the http status code - response=$(curl -skS -w "%{http_code}" -X GET "${API_URL}$1" -H "Accept: application/json" -H "sid: ${SID}" ) + response=$(curl -skS -w "%{http_code}" -X GET "${API_URL}$1" -H "Accept: application/json" -H "sid: ${SID}" ) # status are the last 3 characters status=$(printf %s "${response#"${response%???}"}") From d1707e56a51a1398bf85c8cb482c5e901841347a Mon Sep 17 00:00:00 2001 From: yubiuser Date: Thu, 18 Jul 2024 08:51:01 +0200 Subject: [PATCH 59/96] Check for required dependencies on startup Signed-off-by: yubiuser --- padd.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/padd.sh b/padd.sh index d54f02a..534e09e 100755 --- a/padd.sh +++ b/padd.sh @@ -1330,6 +1330,19 @@ secretRead() { stty "${stty_orig}" } +check_dependencies() { + # Check for required dependencies + if ! command -v curl >/dev/null 2>&1; then + printf "%b" "${check_box_bad} Error!\n 'curl' is missing but required.\n" + exit 1 + fi + + if ! command -v jq >/dev/null 2>&1; then + printf "%b" "${check_box_bad} Error!\n 'jq' is missing but required.\n" + exit 1 + fi +} + ########################################## MAIN FUNCTIONS ########################################## OutputJSON() { @@ -1744,4 +1757,5 @@ while [ "$#" -gt 0 ]; do shift done +check_dependencies main From f918bff7771af0fdd71c3fb0ce3c844a3dd174ed Mon Sep 17 00:00:00 2001 From: yubiuser Date: Thu, 18 Jul 2024 09:54:10 +0200 Subject: [PATCH 60/96] No need to check for wget in update routine as we check for curl during normal runtime Signed-off-by: yubiuser --- padd.sh | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/padd.sh b/padd.sh index 534e09e..4e9a066 100755 --- a/padd.sh +++ b/padd.sh @@ -1613,26 +1613,12 @@ Update() { padd_script_path=$(realpath "$0") - if which wget > /dev/null 2>&1; then - echo "${check_box_info} Downloading PADD update via wget ..." - if wget -qO "${padd_script_path}" https://install.padd.sh > /dev/null 2>&1; then - echo "${check_box_good} ... done. Restart PADD for the update to take effect" - else - echo "${check_box_bad} Cannot download PADD update via wget" - echo "${check_box_info} Go to https://install.padd.sh to download the update manually" - exit 1 - fi - elif which curl > /dev/null 2>&1; then - echo "${check_box_info} Downloading PADD update via curl ..." - if curl -sSL https://install.padd.sh -o "${padd_script_path}" > /dev/null 2>&1; then - echo "${check_box_good} ... done. Restart PADD for the update to take effect" - else - echo "${check_box_bad} Cannot download PADD update via curl" - echo "${check_box_info} Go to https://install.padd.sh to download the update manually" - exit 1 - fi + echo "${check_box_info} Downloading PADD update ..." + + if curl -sSL https://install.padd.sh -o "${padd_script_path}" > /dev/null 2>&1; then + echo "${check_box_good} ... done. Restart PADD for the update to take effect" else - echo "${check_box_bad} Cannot download, neither wget nor curl are available" + echo "${check_box_bad} Cannot download PADD update" echo "${check_box_info} Go to https://install.padd.sh to download the update manually" exit 1 fi @@ -1720,6 +1706,9 @@ TerminalResize(){ } main(){ + + check_dependencies + # Hiding the cursor. # https://vt100.net/docs/vt510-rm/DECTCEM.html printf '\e[?25l' @@ -1757,5 +1746,4 @@ while [ "$#" -gt 0 ]; do shift done -check_dependencies main From ef97d5bd578b99da828fa98825afcd0ed7d17e93 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 22 Jul 2024 14:16:29 +0200 Subject: [PATCH 61/96] Fallback: If there is no default IPv6 gateway, use the default IPv4 gateway interface instead Signed-off-by: DL6ER --- padd.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/padd.sh b/padd.sh index 3790471..83e3b31 100755 --- a/padd.sh +++ b/padd.sh @@ -394,6 +394,11 @@ GetNetworkInformation() { gateway_v4_iface=$(echo "${gateway_raw}" | jq -r '.gateway[] | select(.family == "inet") | .interface' | head -n 1) v4_iface_data=$(echo "${interfaces_raw}" | jq --arg iface "${gateway_v4_iface}" '.interfaces[] | select(.name==$iface)' 2>/dev/null) gateway_v6_iface=$(echo "${gateway_raw}" | jq -r '.gateway[] | select(.family == "inet6") | .interface' | head -n 1) + # Fallback: If there is no default IPv6 gateway, use the default IPv4 + # gateway interface instead + if [ -z "${gateway_v6_iface}" ]; then + gateway_v6_iface="${gateway_v4_iface}" + fi v6_iface_data=$(echo "${interfaces_raw}" | jq --arg iface "${gateway_v6_iface}" '.interfaces[] | select(.name==$iface)' 2>/dev/null) config=$(GetFTLData "config") From 5559796a4a574910f4797f40c9112130bb9f23e0 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 5 Aug 2024 19:01:55 +0200 Subject: [PATCH 62/96] Use new FTL api/padd endpoint for querying the data Signed-off-by: DL6ER --- padd.sh | 256 ++++++++++++++++++++++++++------------------------------ 1 file changed, 117 insertions(+), 139 deletions(-) diff --git a/padd.sh b/padd.sh index f78aa78..90fd569 100755 --- a/padd.sh +++ b/padd.sh @@ -18,12 +18,8 @@ export LC_NUMERIC=C padd_version="v4.0.0" # LastChecks -LastCheckVersionInformation=$(date +%s) -LastCheckNetworkInformation=$(date +%s) -LastCheckSummaryInformation=$(date +%s) -LastCheckPiholeInformation=$(date +%s) -LastCheckSystemInformation=$(date +%s) LastCheckPADDInformation=$(date +%s) +LastCheckFullInformation=$(date +%s) # COLORS CSI="$(printf '\033')[" # Control Sequence Introducer @@ -247,7 +243,7 @@ Authenticate() { GetFTLData() { local response # get the data from querying the API as well as the http status code - response=$(curl -skS -w "%{http_code}" -X GET "${API_URL}$1" -H "Accept: application/json" -H "sid: ${SID}" ) + response=$(curl -skS -w "%{http_code}" -X GET "${API_URL}$1$2" -H "Accept: application/json" -H "sid: ${SID}" ) # status are the last 3 characters status=$(printf %s "${response#"${response%???}"}") @@ -268,61 +264,55 @@ GetFTLData() { ############################################# GETTERS ############################################## +GetAPIData() { + padd_data=$(GetFTLData "padd" "$1") + echo "$padd_data" > data.json +} + GetSummaryInformation() { - summary=$(GetFTLData "stats/summary") - cache_info=$(GetFTLData "info/metrics") - ftl_info=$(GetFTLData "info/ftl") - dns_blocking=$(GetFTLData "dns/blocking") + clients=$(echo "${padd_data}" | jq .active_clients 2>/dev/null) - clients=$(echo "${ftl_info}" | jq .ftl.clients.active 2>/dev/null) + blocking_enabled=$(echo "${padd_data}" | jq .blocking 2>/dev/null) - blocking_enabled=$(echo "${dns_blocking}" | jq .blocking 2>/dev/null) - - domains_being_blocked_raw=$(echo "${ftl_info}" | jq .ftl.database.gravity 2>/dev/null) + domains_being_blocked_raw=$(echo "${padd_data}" | jq .gravity_size 2>/dev/null) domains_being_blocked=$(printf "%.f" "${domains_being_blocked_raw}") - dns_queries_today_raw=$(echo "$summary" | jq .queries.total 2>/dev/null) + dns_queries_today_raw=$(echo "${padd_data}" | jq .queries.total 2>/dev/null) dns_queries_today=$(printf "%.f" "${dns_queries_today_raw}") - ads_blocked_today_raw=$(echo "$summary" | jq .queries.blocked 2>/dev/null) + ads_blocked_today_raw=$(echo "${padd_data}" | jq .queries.blocked 2>/dev/null) ads_blocked_today=$(printf "%.f" "${ads_blocked_today_raw}") - ads_percentage_today_raw=$(echo "$summary" | jq .queries.percent_blocked 2>/dev/null) + ads_percentage_today_raw=$(echo "${padd_data}" | jq .queries.percent_blocked 2>/dev/null) ads_percentage_today=$(printf "%.1f" "${ads_percentage_today_raw}") - cache_size=$(echo "$cache_info" | jq .metrics.dns.cache.size 2>/dev/null) - cache_evictions=$(echo "$cache_info" | jq .metrics.dns.cache.evicted 2>/dev/null) - cache_inserts=$(echo "$cache_info"| jq .metrics.dns.cache.inserted 2>/dev/null) + cache_size=$(echo "${padd_data}" | jq .cache.size 2>/dev/null) + cache_evictions=$(echo "${padd_data}" | jq .cache.evicted 2>/dev/null) + cache_inserts=$(echo "${padd_data}"| jq .cache.inserted 2>/dev/null) - latest_blocked_raw=$(GetFTLData "stats/recent_blocked?show=1" | jq --raw-output .blocked[0] 2>/dev/null) + latest_blocked_raw=$(echo "${padd_data}" | jq --raw-output .recent_blocked 2>/dev/null) - top_blocked_raw=$(GetFTLData "stats/top_domains?blocked=true" | jq --raw-output .domains[0].domain 2>/dev/null) + top_blocked_raw=$(echo "${padd_data}" | jq --raw-output .top_domain 2>/dev/null) - top_domain_raw=$(GetFTLData "stats/top_domains" | jq --raw-output .domains[0].domain 2>/dev/null) + top_domain_raw=$(echo "${padd_data}" | jq --raw-output .top_blocked 2>/dev/null) - top_client_raw=$(GetFTLData "stats/top_clients" | jq --raw-output .clients[0].name 2>/dev/null) - if [ -z "${top_client_raw}" ]; then - # if no hostname was supplied, use IP - top_client_raw=$(GetFTLData "stats/top_clients" | jq --raw-output .clients[0].ip 2>/dev/null) - fi + top_client_raw=$(echo "${padd_data}" | jq --raw-output .top_client 2>/dev/null) } GetSystemInformation() { - sysinfo=$(GetFTLData "info/system") - # System uptime - if [ "${sysinfo}" = 000 ]; then + if [ "${padd_data}" = 000 ]; then # in case FTL connection is down, system_uptime_raw need to be set to 0 otherwise convertUptime() will complain system_uptime_raw=0 else - system_uptime_raw=$(echo "${sysinfo}" | jq .system.uptime 2>/dev/null) + system_uptime_raw=$(echo "${padd_data}" | jq .system.uptime 2>/dev/null) fi # CPU temperature and unit # in case .sensors.cpu_temp returns 'null' we substitute with 0 - cpu_temp_raw=$(GetFTLData "info/sensors" | jq '(.sensors.cpu_temp // 0)' 2>/dev/null) + cpu_temp_raw=$(echo "${padd_data}" | jq '(.sensors.cpu_temp // 0)' 2>/dev/null) cpu_temp=$(printf "%.1f" "${cpu_temp_raw}") - temp_unit=$(GetFTLData "info/sensors" | jq --raw-output .sensors.unit 2>/dev/null) + temp_unit=$(echo "${padd_data}" | jq --raw-output .sensors.unit 2>/dev/null) # Temp + Unit if [ "${temp_unit}" = "C" ]; then @@ -338,6 +328,10 @@ GetSystemInformation() { temperature="${cpu_temp}${temp_unit}" # convert to Celsius for limit checking cpu_temp_celsius="$(echo "${cpu_temp}" | awk '{print $1 - 273.15}' | awk -F '.' '{print $1}')" + else # unknown unit + temperature="${cpu_temp}°?" + # no conversion needed + cpu_temp_celsius=0 fi # CPU temperature heatmap @@ -356,22 +350,22 @@ GetSystemInformation() { fi # CPU, load, heatmap - core_count=$(echo "${sysinfo}" | jq .system.cpu.nprocs 2>/dev/null) - cpu_load_1=$(printf %.2f "$(echo "${sysinfo}" | jq .system.cpu.load.raw[0] 2>/dev/null)") - cpu_load_5=$(printf %.2f "$(echo "${sysinfo}" | jq .system.cpu.load.raw[1] 2>/dev/null)") - cpu_load_15=$(printf %.2f "$(echo "${sysinfo}" | jq .system.cpu.load.raw[2] 2>/dev/null)") + core_count=$(echo "${padd_data}" | jq .system.cpu.nprocs 2>/dev/null) + cpu_load_1=$(printf %.2f "$(echo "${padd_data}" | jq .system.cpu.load.raw[0] 2>/dev/null)") + cpu_load_5=$(printf %.2f "$(echo "${padd_data}" | jq .system.cpu.load.raw[1] 2>/dev/null)") + cpu_load_15=$(printf %.2f "$(echo "${padd_data}" | jq .system.cpu.load.raw[2] 2>/dev/null)") cpu_load_1_heatmap=$(HeatmapGenerator "${cpu_load_1}" "${core_count}") cpu_load_5_heatmap=$(HeatmapGenerator "${cpu_load_5}" "${core_count}") cpu_load_15_heatmap=$(HeatmapGenerator "${cpu_load_15}" "${core_count}") - cpu_percent=$(printf %.1f "$(echo "${sysinfo}" | jq .system.cpu.load.percent[0] 2>/dev/null)") + cpu_percent=$(printf %.1f "$(echo "${padd_data}" | jq .system.cpu.load.percent[0] 2>/dev/null)") # Memory use, heatmap and bar - memory_percent_raw="$(echo "${sysinfo}" | jq '.system.memory.ram."%used"' 2>/dev/null)" + memory_percent_raw="$(echo "${padd_data}" | jq '.system.memory.ram."%used"' 2>/dev/null)" memory_percent=$(printf %.1f "${memory_percent_raw}") memory_heatmap="$(HeatmapGenerator "${memory_percent}")" # Get device model - sys_model="$(GetFTLData "info/host" | jq --raw-output .host.model 2>/dev/null)" + sys_model="$(echo "${padd_data}" | jq --raw-output .host_model 2>/dev/null)" # DOCKER_VERSION is set during GetVersionInformation, so this needs to run first during startup if [ ! "${DOCKER_VERSION}" = "null" ]; then @@ -389,54 +383,44 @@ GetSystemInformation() { } GetNetworkInformation() { - interfaces_raw=$(GetFTLData "network/interfaces") - gateway_raw=$(GetFTLData "network/gateway") - gateway_v4_iface=$(echo "${gateway_raw}" | jq -r '.gateway[] | select(.family == "inet") | .interface' | head -n 1) - v4_iface_data=$(echo "${interfaces_raw}" | jq --arg iface "${gateway_v4_iface}" '.interfaces[] | select(.name==$iface)' 2>/dev/null) - gateway_v6_iface=$(echo "${gateway_raw}" | jq -r '.gateway[] | select(.family == "inet6") | .interface' | head -n 1) - # Fallback: If there is no default IPv6 gateway, use the default IPv4 - # gateway interface instead - if [ -z "${gateway_v6_iface}" ]; then - gateway_v6_iface="${gateway_v4_iface}" - fi - v6_iface_data=$(echo "${interfaces_raw}" | jq --arg iface "${gateway_v6_iface}" '.interfaces[] | select(.name==$iface)' 2>/dev/null) - config=$(GetFTLData "config") + gateway_v4_iface=$(echo "${padd_data}" | jq -r '.iface.v4.name') + gateway_v6_iface=$(echo "${padd_data}" | jq -r '.iface.v4.name') - # Get pi IPv4 address of the default interface - pi_ip4_addrs="$(echo "${v4_iface_data}" | jq --raw-output '.addresses[] | select(.family=="inet") | .address' 2>/dev/null)" - if [ $(echo "${pi_ip4_addrs}" | wc -l) -eq 0 ]; then + # Get IPv4 address of the default interface + pi_ip4_addrs="$(echo "${padd_data}" | jq --raw-output '.iface.v4.num_addrs' 2>/dev/null)" + pi_ip4_addr="$(echo "${padd_data}" | jq --raw-output '.iface.v4.addr' 2>/dev/null)" + if [ "${pi_ip4_addrs}" -eq 0 ]; then # No IPv4 address available pi_ip4_addr="N/A" - elif [ $(echo "${pi_ip4_addrs}" | wc -l) -eq 1 ]; then - # One IPv4 address available - pi_ip4_addr=${pi_ip4_addrs} + #elif [ "${pi_ip4_addrs}" -eq 1 ]; then + # # One IPv4 address available else # More than one IPv4 address available - pi_ip4_addr="$(echo "${pi_ip4_addrs}" | head -n 1)+" + pi_ip4_addr="${pi_ip4_addr}+" fi - # Get pi IPv6 address of the default interface - pi_ip6_addrs="$(echo "${v6_iface_data}" | jq --raw-output '.addresses[] | select(.family=="inet6") | .address' 2>/dev/null)" - if [ $(echo "${pi_ip6_addrs}" | wc -l) -eq 0 ]; then + # Get IPv6 address of the default interface + pi_ip6_addrs="$(echo "${padd_data}" | jq --raw-output '.iface.v6.num_addrs' 2>/dev/null)" + pi_ip6_addr="$(echo "${padd_data}" | jq --raw-output '.iface.v6.addr' 2>/dev/null)" + if [ "${pi_ip6_addrs}" -eq 0 ]; then # No IPv6 address available pi_ip6_addr="N/A" ipv6_check_box=${check_box_bad} - elif [ $(echo "${pi_ip6_addrs}" | wc -l) -eq 1 ]; then + elif [ "${pi_ip6_addrs}" -eq 1 ]; then # One IPv6 address available - pi_ip6_addr=${pi_ip6_addrs} ipv6_check_box=${check_box_good} else # More than one IPv6 address available - pi_ip6_addr="$(echo "${pi_ip6_addrs}" | head -n 1)+" + pi_ip6_addr="${pi_ip6_addr}+" ipv6_check_box=${check_box_good} fi # Is Pi-Hole acting as the DHCP server? - DHCP_ACTIVE="$(echo "${config}" | jq .config.dhcp.active 2>/dev/null )" + DHCP_ACTIVE="$(echo "${padd_data}" | jq .config.dhcp_active 2>/dev/null )" if [ "${DHCP_ACTIVE}" = "true" ]; then - DHCP_START="$(echo "${config}" | jq --raw-output .config.dhcp.start 2>/dev/null)" - DHCP_END="$(echo "${config}" | jq --raw-output .config.dhcp.end 2>/dev/null)" + DHCP_START="$(echo "${padd_data}" | jq --raw-output .config.dhcp_start 2>/dev/null)" + DHCP_END="$(echo "${padd_data}" | jq --raw-output .config.dhcp_end 2>/dev/null)" dhcp_status="Enabled" dhcp_info=" Range: ${DHCP_START} - ${DHCP_END}" @@ -444,7 +428,7 @@ GetNetworkInformation() { dhcp_check_box=${check_box_good} # Is DHCP handling IPv6? - DHCP_IPv6="$(echo "${config}" | jq --raw-output .config.dhcp.ipv6 2>/dev/null)" + DHCP_IPv6="$(echo "${padd_data}" | jq --raw-output .config.dhcp_ipv6 2>/dev/null)" if [ "${DHCP_IPv6}" = "true" ]; then dhcp_ipv6_status="Enabled" dhcp_ipv6_heatmap=${green_text} @@ -460,7 +444,7 @@ GetNetworkInformation() { dhcp_check_box=${check_box_bad} # Display the gateway address if DHCP is disabled - GATEWAY="$(echo "${gateway_raw}" | jq -r '.gateway[] | select(.family == "inet") | .address' | head -n 1)" + GATEWAY="$(echo "${padd_data}" | jq -r '.iface.v4.gw_addr' | head -n 1)" dhcp_info=" Router: ${GATEWAY}" dhcp_ipv6_status="N/A" dhcp_ipv6_heatmap=${yellow_text} @@ -468,11 +452,11 @@ GetNetworkInformation() { fi # Get hostname - pi_hostname="$(GetFTLData "info/host" | jq --raw-output .host.uname.nodename 2>/dev/null)" + pi_hostname="$(echo "${padd_data}" | jq --raw-output .node_name 2>/dev/null)" full_hostname=${pi_hostname} # when PI-hole is the DHCP server, append the domain to the hostname if [ "${DHCP_ACTIVE}" = "true" ]; then - PIHOLE_DOMAIN="$(echo "${config}" | jq --raw-output .config.dns.domain 2>/dev/null)" + PIHOLE_DOMAIN="$(echo "${padd_data}" | jq --raw-output .config.dns_domain 2>/dev/null)" if [ -n "${PIHOLE_DOMAIN}" ]; then count=${pi_hostname}"."${PIHOLE_DOMAIN} count=${#count} @@ -483,7 +467,7 @@ GetNetworkInformation() { fi # Get the number of configured upstream DNS servers - dns_count="$(echo "${config}" | jq --raw-output .config.dns.upstreams[] 2>/dev/null | sed '/^\s*$/d' | wc -l)" + dns_count="$(echo "${padd_data}" | jq --raw-output .config.dns_num_upstreams 2>/dev/null)" # if there's only one DNS server if [ "${dns_count}" -eq 1 ]; then dns_information="1 server" @@ -493,7 +477,7 @@ GetNetworkInformation() { # DNSSEC - DNSSEC="$(echo "${config}" | jq .config.dns.dnssec 2>/dev/null)" + DNSSEC="$(echo "${padd_data}" | jq .config.dns_dnssec 2>/dev/null)" if [ "${DNSSEC}" = "true" ]; then dnssec_status="Enabled" dnssec_heatmap=${green_text} @@ -503,7 +487,7 @@ GetNetworkInformation() { fi # Conditional forwarding - CONDITIONAL_FORWARDING="$(echo "${config}" | jq .config.dns.revServer.active 2>/dev/null)" + CONDITIONAL_FORWARDING="$(echo "${padd_data}" | jq .config.dns_revServer_active 2>/dev/null)" if [ "${CONDITIONAL_FORWARDING}" = "true" ]; then conditional_forwarding_status="Enabled" conditional_forwarding_heatmap=${green_text} @@ -514,12 +498,12 @@ GetNetworkInformation() { # Default interface data (use IPv4 interface - we cannot show both and assume they are the same) iface_name="${gateway_v4_iface}" - tx_bytes="$(echo "${v4_iface_data}" | jq --raw-output '.stats.tx_bytes.value' 2>/dev/null)" - tx_bytes_unit="$(echo "${v4_iface_data}" | jq --raw-output '.stats.tx_bytes.unit' 2>/dev/null)" + tx_bytes="$(echo "${padd_data}" | jq --raw-output '.iface.v4.tx_bytes.value' 2>/dev/null)" + tx_bytes_unit="$(echo "${padd_data}" | jq --raw-output '.iface.v4.tx_bytes.unit' 2>/dev/null)" tx_bytes=$(printf "%.1f %b" "${tx_bytes}" "${tx_bytes_unit}") - rx_bytes="$(echo "${v4_iface_data}" | jq --raw-output '.stats.rx_bytes.value' 2>/dev/null)" - rx_bytes_unit="$(echo "${v4_iface_data}" | jq --raw-output '.stats.rx_bytes.unit' 2>/dev/null)" + rx_bytes="$(echo "${padd_data}" | jq --raw-output '.iface.v4.rx_bytes.value' 2>/dev/null)" + rx_bytes_unit="$(echo "${padd_data}" | jq --raw-output '.iface.v4.rx_bytes.unit' 2>/dev/null)" rx_bytes=$(printf "%.1f %b" "${rx_bytes}" "${rx_bytes_unit}") # If IPv4 and IPv6 interfaces are not the same, add a "*" to the interface @@ -532,11 +516,9 @@ GetNetworkInformation() { } GetPiholeInformation() { - sysinfo=$(GetFTLData "info/ftl") - # If FTL is not running (sysinfo is 000), set all variables to "not running" connection_down_flag=false - if [ "${sysinfo}" = "000" ]; then + if [ "${padd_data}" = "000" ]; then ftl_status="No connection" ftl_heatmap=${red_text} ftl_check_box=${check_box_bad} @@ -549,14 +531,14 @@ GetPiholeInformation() { ftl_heatmap=${green_text} ftl_check_box=${check_box_good} # Get FTL CPU and memory usage - ftl_cpu_raw="$(echo "${sysinfo}" | jq '.ftl."%cpu"' 2>/dev/null)" - ftl_mem_percentage_raw="$(echo "${sysinfo}" | jq '.ftl."%mem"' 2>/dev/null)" + ftl_cpu_raw="$(echo "${padd_data}" | jq '."%cpu"' 2>/dev/null)" + ftl_mem_percentage_raw="$(echo "${padd_data}" | jq '."%mem"' 2>/dev/null)" ftl_cpu="$(printf "%.1f" "${ftl_cpu_raw}")%" ftl_mem_percentage="$(printf "%.1f" "${ftl_mem_percentage_raw}")%" # Get Pi-hole (blocking) status - ftl_dns_port=$(GetFTLData "config" | jq .config.dns.port 2>/dev/null) + ftl_dns_port=$(echo "${padd_data}" | jq .config.dns_port 2>/dev/null) # Get FTL's current PID - ftlPID="$(echo "${sysinfo}" | jq .ftl.pid 2>/dev/null)" + ftlPID="$(echo "${padd_data}" | jq .pid 2>/dev/null)" fi @@ -579,15 +561,14 @@ fi GetVersionInformation() { out_of_date_flag=false - versions_raw=$(GetFTLData "info/version") # Gather DOCKER version information... # returns "null" if not running Pi-hole in Docker container - DOCKER_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.docker.local 2>/dev/null)" + DOCKER_VERSION="$(echo "${padd_data}" | jq --raw-output .version.docker.local 2>/dev/null)" # If PADD is running inside docker, immediately return without checking for updated component versions if [ ! "${DOCKER_VERSION}" = "null" ] ; then - GITHUB_DOCKER_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.docker.remote 2>/dev/null)" + GITHUB_DOCKER_VERSION="$(echo "${padd_data}" | jq --raw-output .version.docker.remote 2>/dev/null)" docker_version_converted="$(VersionConverter "${DOCKER_VERSION}")" docker_version_latest_converted="$(VersionConverter "${GITHUB_DOCKER_VERSION}")" @@ -604,11 +585,11 @@ GetVersionInformation() { fi # Gather core version information... - CORE_BRANCH="$(echo "${versions_raw}" | jq --raw-output .version.core.local.branch 2>/dev/null)" - CORE_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.core.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_CORE_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.core.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - CORE_HASH="$(echo "${versions_raw}" | jq --raw-output .version.core.local.hash 2>/dev/null)" - GITHUB_CORE_HASH="$(echo "${versions_raw}" | jq --raw-output .version.core.remote.hash 2>/dev/null)" + CORE_BRANCH="$(echo "${padd_data}" | jq --raw-output .version.core.local.branch 2>/dev/null)" + CORE_VERSION="$(echo "${padd_data}" | jq --raw-output .version.core.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_CORE_VERSION="$(echo "${padd_data}" | jq --raw-output .version.core.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + CORE_HASH="$(echo "${padd_data}" | jq --raw-output .version.core.local.hash 2>/dev/null)" + GITHUB_CORE_HASH="$(echo "${padd_data}" | jq --raw-output .version.core.remote.hash 2>/dev/null)" if [ "${CORE_BRANCH}" = "master" ]; then core_version_converted="$(VersionConverter "${CORE_VERSION}")" @@ -642,14 +623,14 @@ GetVersionInformation() { fi # Gather web version information... - WEB_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.web.local.version 2>/dev/null)" + WEB_VERSION="$(echo "${padd_data}" | jq --raw-output .version.web.local.version 2>/dev/null)" if [ ! "$WEB_VERSION" = "null" ]; then - WEB_BRANCH="$(echo "${versions_raw}" | jq --raw-output .version.web.local.branch 2>/dev/null)" - WEB_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.web.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_WEB_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.web.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - WEB_HASH="$(echo "${versions_raw}" | jq --raw-output .version.web.local.hash 2>/dev/null)" - GITHUB_WEB_HASH="$(echo "${versions_raw}" | jq --raw-output .version.web.remote.hash 2>/dev/null)" + WEB_BRANCH="$(echo "${padd_data}" | jq --raw-output .version.web.local.branch 2>/dev/null)" + WEB_VERSION="$(echo "${padd_data}" | jq --raw-output .version.web.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_WEB_VERSION="$(echo "${padd_data}" | jq --raw-output .version.web.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + WEB_HASH="$(echo "${padd_data}" | jq --raw-output .version.web.local.hash 2>/dev/null)" + GITHUB_WEB_HASH="$(echo "${padd_data}" | jq --raw-output .version.web.remote.hash 2>/dev/null)" if [ "${WEB_BRANCH}" = "master" ]; then web_version_converted="$(VersionConverter "${WEB_VERSION}")" @@ -689,11 +670,11 @@ GetVersionInformation() { fi # Gather FTL version information... - FTL_BRANCH="$(echo "${versions_raw}" | jq --raw-output .version.ftl.local.branch 2>/dev/null)" - FTL_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.ftl.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_FTL_VERSION="$(echo "${versions_raw}" | jq --raw-output .version.ftl.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - FTL_HASH="$(echo "${versions_raw}" | jq --raw-output .version.ftl.local.hash 2>/dev/null)" - GITHUB_FTL_HASH="$(echo "${versions_raw}" | jq --raw-output .version.ftl.remote.hash 2>/dev/null)" + FTL_BRANCH="$(echo "${padd_data}" | jq --raw-output .version.ftl.local.branch 2>/dev/null)" + FTL_VERSION="$(echo "${padd_data}" | jq --raw-output .version.ftl.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_FTL_VERSION="$(echo "${padd_data}" | jq --raw-output .version.ftl.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + FTL_HASH="$(echo "${padd_data}" | jq --raw-output .version.ftl.local.hash 2>/dev/null)" + GITHUB_FTL_HASH="$(echo "${padd_data}" | jq --raw-output .version.ftl.remote.hash 2>/dev/null)" if [ "${FTL_BRANCH}" = "master" ]; then @@ -1155,7 +1136,7 @@ BarGenerator() { echo "$out" } -# Checks the size of the screen and sets the value of $padd_size +# Checks the size of the screen and sets the value of ${padd_data}_size SizeChecker(){ # adding a tiny delay here to to give the kernel a bit time to # report new sizes correctly after a terminal resize @@ -1381,6 +1362,7 @@ OutputJSON() { printf "%b" "Establishing connection with FTL...\n" LoginAPI + GetAPIData GetSummaryInformation printf "%b" "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today},\"clients\": ${clients}}" } @@ -1444,6 +1426,9 @@ StartupRoutine(){ moveXOffset; printf "%b" " [■·········] 10%\r" + # Request API data + GetAPIData + # Check for updates moveXOffset; printf "%b" " [■■········] 20%\r" moveXOffset; printf "%b" " [■■■·······] 30%\r" @@ -1472,12 +1457,16 @@ StartupRoutine(){ moveXOffset; printf "%b" "Establishing connection with FTL...\n" LoginAPI + # Request API data + moveXOffset; echo "- Requesting API information..." + GetAPIData + # Get our information for the first time moveXOffset; echo "- Gathering version info." GetVersionInformation moveXOffset; echo "- Gathering system info." GetSystemInformation - moveXOffset; echo "- Gathering Pi-hole info." + moveXOffset; echo "- Gathering CPU/DNS info." GetPiholeInformation GetSummaryInformation moveXOffset; echo "- Gathering network info." @@ -1487,7 +1476,7 @@ StartupRoutine(){ moveXOffset; echo " - Docker Tag ${DOCKER_VERSION}" else moveXOffset; echo " - Core $CORE_VERSION, Web $WEB_VERSION" - moveXOffset; echo " - FTL $FTL_VERSION, PADD $padd_version" + moveXOffset; echo " - FTL $FTL_VERSION, PADD ${padd_data}_version" fi else @@ -1507,13 +1496,16 @@ StartupRoutine(){ moveXOffset; printf "%b" "Establishing connection with FTL...\n" LoginAPI + # Request API data + moveXOffset; echo "- Requesting API information..." + GetAPIData # Get our information for the first time moveXOffset; echo "- Gathering version information..." GetVersionInformation moveXOffset; echo "- Gathering system information..." GetSystemInformation - moveXOffset; echo "- Gathering Pi-hole information..." + moveXOffset; echo "- Gathering CPU/DNS information..." GetSummaryInformation GetPiholeInformation moveXOffset; echo "- Gathering network information..." @@ -1526,7 +1518,7 @@ StartupRoutine(){ moveXOffset; echo " - Pi-hole Core $CORE_VERSION" moveXOffset; echo " - Web Admin $WEB_VERSION" moveXOffset; echo " - FTL $FTL_VERSION" - moveXOffset; echo " - PADD $padd_version" + moveXOffset; echo " - PADD ${padd_version}" fi fi @@ -1577,35 +1569,21 @@ NormalPADD() { Authenticate fi + # Request API data + if [ $((now - LastCheckFullInformation)) -ge 30 ]; then + GetAPIData + GetNetworkInformation + GetVersionInformation + LastCheckFullInformation="${now}" + else + # Request only a subset of the data + GetAPIData "?full=false" + fi + # Get uptime, CPU load, temp, etc. every 5 seconds - if [ $((now - LastCheckSystemInformation)) -ge 5 ]; then - GetSystemInformation - LastCheckSystemInformation="${now}" - fi - - # Get cache info, last ad domain, blocking percentage, etc. every 5 seconds - if [ $((now - LastCheckSummaryInformation)) -ge 5 ]; then - GetSummaryInformation - LastCheckSummaryInformation="${now}" - fi - - # Get FTL status every 5 seconds - if [ $((now - LastCheckPiholeInformation)) -ge 5 ]; then - GetPiholeInformation - LastCheckPiholeInformation="${now}" - fi - - # Get IPv4 address, DNS servers, DNSSEC, hostname, DHCP status, interface traffic, etc. every 30 seconds - if [ $((now - LastCheckNetworkInformation)) -ge 30 ]; then - GetNetworkInformation - LastCheckNetworkInformation="${now}" - fi - - # Get Pi-hole components version information every 30 seconds - if [ $((now - LastCheckVersionInformation)) -ge 30 ]; then - GetVersionInformation - LastCheckVersionInformation="${now}" - fi + GetSystemInformation + GetSummaryInformation + GetPiholeInformation # Get PADD version information every 24hours if [ $((now - LastCheckPADDInformation)) -ge 86400 ]; then From 113ef44b3774f2696c3bf2ad82b0372b5dd0a54b Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 7 Aug 2024 20:25:11 +0200 Subject: [PATCH 63/96] Use jq only once for parsing the entire payload after querying the API Signed-off-by: DL6ER --- padd.sh | 143 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 76 insertions(+), 67 deletions(-) diff --git a/padd.sh b/padd.sh index 90fd569..35990d9 100755 --- a/padd.sh +++ b/padd.sh @@ -265,38 +265,47 @@ GetFTLData() { ############################################# GETTERS ############################################## GetAPIData() { - padd_data=$(GetFTLData "padd" "$1") - echo "$padd_data" > data.json + local api_data + api_data=$(GetFTLData "padd" "$1") + # Iterate over all the leaf paths in the JSON object and creates key-value + # pairs in the format "key=value". Nested objects are flattened using the dot + # notation, e.g., { "a": { "b": 1 } } becomes "a.b=1". The resulting key-value + # pairs are then stored in the variable `padd_data`. + padd_data=$(echo "$api_data" | jq -r '[leaf_paths as $path | { "key": $path | join("."), "value": getpath($path) }] | map("\(.key)=\(.value|tostring)") | .[]') +} + +GetAPIValue() { + echo "$padd_data" | sed -n "s/^$1=//p" } GetSummaryInformation() { - clients=$(echo "${padd_data}" | jq .active_clients 2>/dev/null) + clients=$(GetAPIValue active_clients 2>/dev/null) - blocking_enabled=$(echo "${padd_data}" | jq .blocking 2>/dev/null) + blocking_enabled=$(GetAPIValue blocking 2>/dev/null) - domains_being_blocked_raw=$(echo "${padd_data}" | jq .gravity_size 2>/dev/null) + domains_being_blocked_raw=$(GetAPIValue gravity_size 2>/dev/null) domains_being_blocked=$(printf "%.f" "${domains_being_blocked_raw}") - dns_queries_today_raw=$(echo "${padd_data}" | jq .queries.total 2>/dev/null) + dns_queries_today_raw=$(GetAPIValue queries.total 2>/dev/null) dns_queries_today=$(printf "%.f" "${dns_queries_today_raw}") - ads_blocked_today_raw=$(echo "${padd_data}" | jq .queries.blocked 2>/dev/null) + ads_blocked_today_raw=$(GetAPIValue queries.blocked 2>/dev/null) ads_blocked_today=$(printf "%.f" "${ads_blocked_today_raw}") - ads_percentage_today_raw=$(echo "${padd_data}" | jq .queries.percent_blocked 2>/dev/null) + ads_percentage_today_raw=$(GetAPIValue queries.percent_blocked 2>/dev/null) ads_percentage_today=$(printf "%.1f" "${ads_percentage_today_raw}") - cache_size=$(echo "${padd_data}" | jq .cache.size 2>/dev/null) - cache_evictions=$(echo "${padd_data}" | jq .cache.evicted 2>/dev/null) - cache_inserts=$(echo "${padd_data}"| jq .cache.inserted 2>/dev/null) + cache_size=$(GetAPIValue cache.size 2>/dev/null) + cache_evictions=$(GetAPIValue cache.evicted 2>/dev/null) + cache_inserts=$(echo "${padd_data}"| GetAPIValue cache.inserted 2>/dev/null) - latest_blocked_raw=$(echo "${padd_data}" | jq --raw-output .recent_blocked 2>/dev/null) + latest_blocked_raw=$(GetAPIValue recent_blocked 2>/dev/null) - top_blocked_raw=$(echo "${padd_data}" | jq --raw-output .top_domain 2>/dev/null) + top_blocked_raw=$(GetAPIValue top_blocked 2>/dev/null) - top_domain_raw=$(echo "${padd_data}" | jq --raw-output .top_blocked 2>/dev/null) + top_domain_raw=$(GetAPIValue top_domain 2>/dev/null) - top_client_raw=$(echo "${padd_data}" | jq --raw-output .top_client 2>/dev/null) + top_client_raw=$(GetAPIValue top_client 2>/dev/null) } GetSystemInformation() { @@ -305,14 +314,14 @@ GetSystemInformation() { # in case FTL connection is down, system_uptime_raw need to be set to 0 otherwise convertUptime() will complain system_uptime_raw=0 else - system_uptime_raw=$(echo "${padd_data}" | jq .system.uptime 2>/dev/null) + system_uptime_raw=$(GetAPIValue system.uptime 2>/dev/null) fi # CPU temperature and unit # in case .sensors.cpu_temp returns 'null' we substitute with 0 - cpu_temp_raw=$(echo "${padd_data}" | jq '(.sensors.cpu_temp // 0)' 2>/dev/null) + cpu_temp_raw=$(GetAPIValue sensors.cpu_temp 2>/dev/null) cpu_temp=$(printf "%.1f" "${cpu_temp_raw}") - temp_unit=$(echo "${padd_data}" | jq --raw-output .sensors.unit 2>/dev/null) + temp_unit=$(echo "${padd_data}" | GetAPIValue sensors.unit 2>/dev/null) # Temp + Unit if [ "${temp_unit}" = "C" ]; then @@ -350,22 +359,22 @@ GetSystemInformation() { fi # CPU, load, heatmap - core_count=$(echo "${padd_data}" | jq .system.cpu.nprocs 2>/dev/null) - cpu_load_1=$(printf %.2f "$(echo "${padd_data}" | jq .system.cpu.load.raw[0] 2>/dev/null)") - cpu_load_5=$(printf %.2f "$(echo "${padd_data}" | jq .system.cpu.load.raw[1] 2>/dev/null)") - cpu_load_15=$(printf %.2f "$(echo "${padd_data}" | jq .system.cpu.load.raw[2] 2>/dev/null)") + core_count=$(GetAPIValue system.cpu.nprocs 2>/dev/null) + cpu_load_1=$(printf %.2f "$(GetAPIValue system.cpu.load.0 2>/dev/null)") + cpu_load_5=$(printf %.2f "$(GetAPIValue system.cpu.load.1 2>/dev/null)") + cpu_load_15=$(printf %.2f "$(GetAPIValue system.cpu.load.2 2>/dev/null)") cpu_load_1_heatmap=$(HeatmapGenerator "${cpu_load_1}" "${core_count}") cpu_load_5_heatmap=$(HeatmapGenerator "${cpu_load_5}" "${core_count}") cpu_load_15_heatmap=$(HeatmapGenerator "${cpu_load_15}" "${core_count}") - cpu_percent=$(printf %.1f "$(echo "${padd_data}" | jq .system.cpu.load.percent[0] 2>/dev/null)") + cpu_percent=$(printf %.1f "$(GetAPIValue system.cpu.load.percent.0 2>/dev/null)") # Memory use, heatmap and bar - memory_percent_raw="$(echo "${padd_data}" | jq '.system.memory.ram."%used"' 2>/dev/null)" + memory_percent_raw="$(GetAPIValue system.memory.ram.%used 2>/dev/null)" memory_percent=$(printf %.1f "${memory_percent_raw}") memory_heatmap="$(HeatmapGenerator "${memory_percent}")" # Get device model - sys_model="$(echo "${padd_data}" | jq --raw-output .host_model 2>/dev/null)" + sys_model="$(GetAPIValue host_model 2>/dev/null)" # DOCKER_VERSION is set during GetVersionInformation, so this needs to run first during startup if [ ! "${DOCKER_VERSION}" = "null" ]; then @@ -383,12 +392,12 @@ GetSystemInformation() { } GetNetworkInformation() { - gateway_v4_iface=$(echo "${padd_data}" | jq -r '.iface.v4.name') - gateway_v6_iface=$(echo "${padd_data}" | jq -r '.iface.v4.name') + gateway_v4_iface=$(GetAPIValue iface.v4.name) + gateway_v6_iface=$(GetAPIValue iface.v4.name) # Get IPv4 address of the default interface - pi_ip4_addrs="$(echo "${padd_data}" | jq --raw-output '.iface.v4.num_addrs' 2>/dev/null)" - pi_ip4_addr="$(echo "${padd_data}" | jq --raw-output '.iface.v4.addr' 2>/dev/null)" + pi_ip4_addrs="$(GetAPIValue iface.v4.num_addrs 2>/dev/null)" + pi_ip4_addr="$(GetAPIValue iface.v4.addr 2>/dev/null)" if [ "${pi_ip4_addrs}" -eq 0 ]; then # No IPv4 address available pi_ip4_addr="N/A" @@ -400,8 +409,8 @@ GetNetworkInformation() { fi # Get IPv6 address of the default interface - pi_ip6_addrs="$(echo "${padd_data}" | jq --raw-output '.iface.v6.num_addrs' 2>/dev/null)" - pi_ip6_addr="$(echo "${padd_data}" | jq --raw-output '.iface.v6.addr' 2>/dev/null)" + pi_ip6_addrs="$(GetAPIValue iface.v6.num_addrs 2>/dev/null)" + pi_ip6_addr="$(GetAPIValue iface.v6.addr 2>/dev/null)" if [ "${pi_ip6_addrs}" -eq 0 ]; then # No IPv6 address available pi_ip6_addr="N/A" @@ -416,11 +425,11 @@ GetNetworkInformation() { fi # Is Pi-Hole acting as the DHCP server? - DHCP_ACTIVE="$(echo "${padd_data}" | jq .config.dhcp_active 2>/dev/null )" + DHCP_ACTIVE="$(GetAPIValue config.dhcp_active 2>/dev/null )" if [ "${DHCP_ACTIVE}" = "true" ]; then - DHCP_START="$(echo "${padd_data}" | jq --raw-output .config.dhcp_start 2>/dev/null)" - DHCP_END="$(echo "${padd_data}" | jq --raw-output .config.dhcp_end 2>/dev/null)" + DHCP_START="$(GetAPIValue config.dhcp_start 2>/dev/null)" + DHCP_END="$(GetAPIValue config.dhcp_end 2>/dev/null)" dhcp_status="Enabled" dhcp_info=" Range: ${DHCP_START} - ${DHCP_END}" @@ -428,7 +437,7 @@ GetNetworkInformation() { dhcp_check_box=${check_box_good} # Is DHCP handling IPv6? - DHCP_IPv6="$(echo "${padd_data}" | jq --raw-output .config.dhcp_ipv6 2>/dev/null)" + DHCP_IPv6="$(GetAPIValue config.dhcp_ipv6 2>/dev/null)" if [ "${DHCP_IPv6}" = "true" ]; then dhcp_ipv6_status="Enabled" dhcp_ipv6_heatmap=${green_text} @@ -444,7 +453,7 @@ GetNetworkInformation() { dhcp_check_box=${check_box_bad} # Display the gateway address if DHCP is disabled - GATEWAY="$(echo "${padd_data}" | jq -r '.iface.v4.gw_addr' | head -n 1)" + GATEWAY="$(GetAPIValue iface.v4.gw_addr | head -n 1)" dhcp_info=" Router: ${GATEWAY}" dhcp_ipv6_status="N/A" dhcp_ipv6_heatmap=${yellow_text} @@ -452,11 +461,11 @@ GetNetworkInformation() { fi # Get hostname - pi_hostname="$(echo "${padd_data}" | jq --raw-output .node_name 2>/dev/null)" + pi_hostname="$(GetAPIValue node_name 2>/dev/null)" full_hostname=${pi_hostname} # when PI-hole is the DHCP server, append the domain to the hostname if [ "${DHCP_ACTIVE}" = "true" ]; then - PIHOLE_DOMAIN="$(echo "${padd_data}" | jq --raw-output .config.dns_domain 2>/dev/null)" + PIHOLE_DOMAIN="$(GetAPIValue config.dns_domain 2>/dev/null)" if [ -n "${PIHOLE_DOMAIN}" ]; then count=${pi_hostname}"."${PIHOLE_DOMAIN} count=${#count} @@ -467,7 +476,7 @@ GetNetworkInformation() { fi # Get the number of configured upstream DNS servers - dns_count="$(echo "${padd_data}" | jq --raw-output .config.dns_num_upstreams 2>/dev/null)" + dns_count="$(GetAPIValue config.dns_num_upstreams 2>/dev/null)" # if there's only one DNS server if [ "${dns_count}" -eq 1 ]; then dns_information="1 server" @@ -477,7 +486,7 @@ GetNetworkInformation() { # DNSSEC - DNSSEC="$(echo "${padd_data}" | jq .config.dns_dnssec 2>/dev/null)" + DNSSEC="$(GetAPIValue config.dns_dnssec 2>/dev/null)" if [ "${DNSSEC}" = "true" ]; then dnssec_status="Enabled" dnssec_heatmap=${green_text} @@ -487,7 +496,7 @@ GetNetworkInformation() { fi # Conditional forwarding - CONDITIONAL_FORWARDING="$(echo "${padd_data}" | jq .config.dns_revServer_active 2>/dev/null)" + CONDITIONAL_FORWARDING="$(GetAPIValue config.dns_revServer_active 2>/dev/null)" if [ "${CONDITIONAL_FORWARDING}" = "true" ]; then conditional_forwarding_status="Enabled" conditional_forwarding_heatmap=${green_text} @@ -498,12 +507,12 @@ GetNetworkInformation() { # Default interface data (use IPv4 interface - we cannot show both and assume they are the same) iface_name="${gateway_v4_iface}" - tx_bytes="$(echo "${padd_data}" | jq --raw-output '.iface.v4.tx_bytes.value' 2>/dev/null)" - tx_bytes_unit="$(echo "${padd_data}" | jq --raw-output '.iface.v4.tx_bytes.unit' 2>/dev/null)" + tx_bytes="$(GetAPIValue iface.v4.tx_bytes.value 2>/dev/null)" + tx_bytes_unit="$(GetAPIValue iface.v4.tx_bytes.unit 2>/dev/null)" tx_bytes=$(printf "%.1f %b" "${tx_bytes}" "${tx_bytes_unit}") - rx_bytes="$(echo "${padd_data}" | jq --raw-output '.iface.v4.rx_bytes.value' 2>/dev/null)" - rx_bytes_unit="$(echo "${padd_data}" | jq --raw-output '.iface.v4.rx_bytes.unit' 2>/dev/null)" + rx_bytes="$(GetAPIValue iface.v4.rx_bytes.value 2>/dev/null)" + rx_bytes_unit="$(GetAPIValue iface.v4.rx_bytes.unit 2>/dev/null)" rx_bytes=$(printf "%.1f %b" "${rx_bytes}" "${rx_bytes_unit}") # If IPv4 and IPv6 interfaces are not the same, add a "*" to the interface @@ -531,14 +540,14 @@ GetPiholeInformation() { ftl_heatmap=${green_text} ftl_check_box=${check_box_good} # Get FTL CPU and memory usage - ftl_cpu_raw="$(echo "${padd_data}" | jq '."%cpu"' 2>/dev/null)" - ftl_mem_percentage_raw="$(echo "${padd_data}" | jq '."%mem"' 2>/dev/null)" + ftl_cpu_raw="$(GetAPIValue "%cpu" 2>/dev/null)" + ftl_mem_percentage_raw="$(GetAPIValue "%mem" 2>/dev/null)" ftl_cpu="$(printf "%.1f" "${ftl_cpu_raw}")%" ftl_mem_percentage="$(printf "%.1f" "${ftl_mem_percentage_raw}")%" # Get Pi-hole (blocking) status - ftl_dns_port=$(echo "${padd_data}" | jq .config.dns_port 2>/dev/null) + ftl_dns_port=$(GetAPIValue config.dns_port 2>/dev/null) # Get FTL's current PID - ftlPID="$(echo "${padd_data}" | jq .pid 2>/dev/null)" + ftlPID="$(GetAPIValue pid 2>/dev/null)" fi @@ -564,11 +573,11 @@ GetVersionInformation() { # Gather DOCKER version information... # returns "null" if not running Pi-hole in Docker container - DOCKER_VERSION="$(echo "${padd_data}" | jq --raw-output .version.docker.local 2>/dev/null)" + DOCKER_VERSION="$(GetAPIValue version.docker.local 2>/dev/null)" # If PADD is running inside docker, immediately return without checking for updated component versions if [ ! "${DOCKER_VERSION}" = "null" ] ; then - GITHUB_DOCKER_VERSION="$(echo "${padd_data}" | jq --raw-output .version.docker.remote 2>/dev/null)" + GITHUB_DOCKER_VERSION="$(GetAPIValue version.docker.remote 2>/dev/null)" docker_version_converted="$(VersionConverter "${DOCKER_VERSION}")" docker_version_latest_converted="$(VersionConverter "${GITHUB_DOCKER_VERSION}")" @@ -585,11 +594,11 @@ GetVersionInformation() { fi # Gather core version information... - CORE_BRANCH="$(echo "${padd_data}" | jq --raw-output .version.core.local.branch 2>/dev/null)" - CORE_VERSION="$(echo "${padd_data}" | jq --raw-output .version.core.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_CORE_VERSION="$(echo "${padd_data}" | jq --raw-output .version.core.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - CORE_HASH="$(echo "${padd_data}" | jq --raw-output .version.core.local.hash 2>/dev/null)" - GITHUB_CORE_HASH="$(echo "${padd_data}" | jq --raw-output .version.core.remote.hash 2>/dev/null)" + CORE_BRANCH="$(GetAPIValue version.core.local.branch 2>/dev/null)" + CORE_VERSION="$(GetAPIValue version.core.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_CORE_VERSION="$(GetAPIValue version.core.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + CORE_HASH="$(GetAPIValue version.core.local.hash 2>/dev/null)" + GITHUB_CORE_HASH="$(GetAPIValue version.core.remote.hash 2>/dev/null)" if [ "${CORE_BRANCH}" = "master" ]; then core_version_converted="$(VersionConverter "${CORE_VERSION}")" @@ -623,14 +632,14 @@ GetVersionInformation() { fi # Gather web version information... - WEB_VERSION="$(echo "${padd_data}" | jq --raw-output .version.web.local.version 2>/dev/null)" + WEB_VERSION="$(GetAPIValue version.web.local.version 2>/dev/null)" if [ ! "$WEB_VERSION" = "null" ]; then - WEB_BRANCH="$(echo "${padd_data}" | jq --raw-output .version.web.local.branch 2>/dev/null)" - WEB_VERSION="$(echo "${padd_data}" | jq --raw-output .version.web.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_WEB_VERSION="$(echo "${padd_data}" | jq --raw-output .version.web.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - WEB_HASH="$(echo "${padd_data}" | jq --raw-output .version.web.local.hash 2>/dev/null)" - GITHUB_WEB_HASH="$(echo "${padd_data}" | jq --raw-output .version.web.remote.hash 2>/dev/null)" + WEB_BRANCH="$(GetAPIValue version.web.local.branch 2>/dev/null)" + WEB_VERSION="$(GetAPIValue version.web.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_WEB_VERSION="$(GetAPIValue version.web.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + WEB_HASH="$(GetAPIValue version.web.local.hash 2>/dev/null)" + GITHUB_WEB_HASH="$(GetAPIValue version.web.remote.hash 2>/dev/null)" if [ "${WEB_BRANCH}" = "master" ]; then web_version_converted="$(VersionConverter "${WEB_VERSION}")" @@ -670,11 +679,11 @@ GetVersionInformation() { fi # Gather FTL version information... - FTL_BRANCH="$(echo "${padd_data}" | jq --raw-output .version.ftl.local.branch 2>/dev/null)" - FTL_VERSION="$(echo "${padd_data}" | jq --raw-output .version.ftl.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_FTL_VERSION="$(echo "${padd_data}" | jq --raw-output .version.ftl.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - FTL_HASH="$(echo "${padd_data}" | jq --raw-output .version.ftl.local.hash 2>/dev/null)" - GITHUB_FTL_HASH="$(echo "${padd_data}" | jq --raw-output .version.ftl.remote.hash 2>/dev/null)" + FTL_BRANCH="$(GetAPIValue version.ftl.local.branch 2>/dev/null)" + FTL_VERSION="$(GetAPIValue version.ftl.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_FTL_VERSION="$(GetAPIValue version.ftl.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + FTL_HASH="$(GetAPIValue version.ftl.local.hash 2>/dev/null)" + GITHUB_FTL_HASH="$(GetAPIValue version.ftl.remote.hash 2>/dev/null)" if [ "${FTL_BRANCH}" = "master" ]; then From 1310ea8f48560922297d73226328b517d95aafe5 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 7 Aug 2024 20:59:41 +0200 Subject: [PATCH 64/96] Redefine jq's paths() as its built-in function skips all pais with values null and false Signed-off-by: DL6ER --- padd.sh | 137 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 70 insertions(+), 67 deletions(-) diff --git a/padd.sh b/padd.sh index 35990d9..b9cbf28 100755 --- a/padd.sh +++ b/padd.sh @@ -269,43 +269,46 @@ GetAPIData() { api_data=$(GetFTLData "padd" "$1") # Iterate over all the leaf paths in the JSON object and creates key-value # pairs in the format "key=value". Nested objects are flattened using the dot - # notation, e.g., { "a": { "b": 1 } } becomes "a.b=1". The resulting key-value - # pairs are then stored in the variable `padd_data`. - padd_data=$(echo "$api_data" | jq -r '[leaf_paths as $path | { "key": $path | join("."), "value": getpath($path) }] | map("\(.key)=\(.value|tostring)") | .[]') + # notation, e.g., { "a": { "b": 1 } } becomes "a.b=1". + # We have to redefine the function here, as it it is broken in jq, see + # https://github.com/jqlang/jq/issues/2872 + # We cannot use leaf_paths here as it was deprecated in jq 1.6 and removed in + # current master + padd_data=$(echo "$api_data" | jq -r 'def paths(node_filter): . as $dot|paths|select(. as $p|$dot|getpath($p)|node_filter|true); paths(scalars) as $p | [$p | join(".")] + [getpath($p)] | join("=")' 2>/dev/null) } GetAPIValue() { - echo "$padd_data" | sed -n "s/^$1=//p" + echo "$padd_data" | sed -n "s/^$1=//p" 2>/dev/null } GetSummaryInformation() { - clients=$(GetAPIValue active_clients 2>/dev/null) + clients=$(GetAPIValue active_clients) - blocking_enabled=$(GetAPIValue blocking 2>/dev/null) + blocking_enabled=$(GetAPIValue blocking) - domains_being_blocked_raw=$(GetAPIValue gravity_size 2>/dev/null) + domains_being_blocked_raw=$(GetAPIValue gravity_size) domains_being_blocked=$(printf "%.f" "${domains_being_blocked_raw}") - dns_queries_today_raw=$(GetAPIValue queries.total 2>/dev/null) + dns_queries_today_raw=$(GetAPIValue queries.total) dns_queries_today=$(printf "%.f" "${dns_queries_today_raw}") - ads_blocked_today_raw=$(GetAPIValue queries.blocked 2>/dev/null) + ads_blocked_today_raw=$(GetAPIValue queries.blocked) ads_blocked_today=$(printf "%.f" "${ads_blocked_today_raw}") - ads_percentage_today_raw=$(GetAPIValue queries.percent_blocked 2>/dev/null) + ads_percentage_today_raw=$(GetAPIValue queries.percent_blocked) ads_percentage_today=$(printf "%.1f" "${ads_percentage_today_raw}") - cache_size=$(GetAPIValue cache.size 2>/dev/null) - cache_evictions=$(GetAPIValue cache.evicted 2>/dev/null) - cache_inserts=$(echo "${padd_data}"| GetAPIValue cache.inserted 2>/dev/null) + cache_size=$(GetAPIValue cache.size) + cache_evictions=$(GetAPIValue cache.evicted) + cache_inserts=$(echo "${padd_data}"| GetAPIValue cache.inserted) - latest_blocked_raw=$(GetAPIValue recent_blocked 2>/dev/null) + latest_blocked_raw=$(GetAPIValue recent_blocked) - top_blocked_raw=$(GetAPIValue top_blocked 2>/dev/null) + top_blocked_raw=$(GetAPIValue top_blocked) - top_domain_raw=$(GetAPIValue top_domain 2>/dev/null) + top_domain_raw=$(GetAPIValue top_domain) - top_client_raw=$(GetAPIValue top_client 2>/dev/null) + top_client_raw=$(GetAPIValue top_client) } GetSystemInformation() { @@ -314,14 +317,14 @@ GetSystemInformation() { # in case FTL connection is down, system_uptime_raw need to be set to 0 otherwise convertUptime() will complain system_uptime_raw=0 else - system_uptime_raw=$(GetAPIValue system.uptime 2>/dev/null) + system_uptime_raw=$(GetAPIValue system.uptime) fi # CPU temperature and unit # in case .sensors.cpu_temp returns 'null' we substitute with 0 - cpu_temp_raw=$(GetAPIValue sensors.cpu_temp 2>/dev/null) + cpu_temp_raw=$(GetAPIValue sensors.cpu_temp) cpu_temp=$(printf "%.1f" "${cpu_temp_raw}") - temp_unit=$(echo "${padd_data}" | GetAPIValue sensors.unit 2>/dev/null) + temp_unit=$(echo "${padd_data}" | GetAPIValue sensors.unit) # Temp + Unit if [ "${temp_unit}" = "C" ]; then @@ -359,22 +362,22 @@ GetSystemInformation() { fi # CPU, load, heatmap - core_count=$(GetAPIValue system.cpu.nprocs 2>/dev/null) - cpu_load_1=$(printf %.2f "$(GetAPIValue system.cpu.load.0 2>/dev/null)") - cpu_load_5=$(printf %.2f "$(GetAPIValue system.cpu.load.1 2>/dev/null)") - cpu_load_15=$(printf %.2f "$(GetAPIValue system.cpu.load.2 2>/dev/null)") + core_count=$(GetAPIValue system.cpu.nprocs) + cpu_load_1=$(printf %.2f "$(GetAPIValue system.cpu.load.0)") + cpu_load_5=$(printf %.2f "$(GetAPIValue system.cpu.load.1)") + cpu_load_15=$(printf %.2f "$(GetAPIValue system.cpu.load.2)") cpu_load_1_heatmap=$(HeatmapGenerator "${cpu_load_1}" "${core_count}") cpu_load_5_heatmap=$(HeatmapGenerator "${cpu_load_5}" "${core_count}") cpu_load_15_heatmap=$(HeatmapGenerator "${cpu_load_15}" "${core_count}") - cpu_percent=$(printf %.1f "$(GetAPIValue system.cpu.load.percent.0 2>/dev/null)") + cpu_percent=$(printf %.1f "$(GetAPIValue system.cpu.load.percent.0)") # Memory use, heatmap and bar - memory_percent_raw="$(GetAPIValue system.memory.ram.%used 2>/dev/null)" + memory_percent_raw="$(GetAPIValue system.memory.ram.%used)" memory_percent=$(printf %.1f "${memory_percent_raw}") memory_heatmap="$(HeatmapGenerator "${memory_percent}")" # Get device model - sys_model="$(GetAPIValue host_model 2>/dev/null)" + sys_model="$(GetAPIValue host_model)" # DOCKER_VERSION is set during GetVersionInformation, so this needs to run first during startup if [ ! "${DOCKER_VERSION}" = "null" ]; then @@ -396,8 +399,8 @@ GetNetworkInformation() { gateway_v6_iface=$(GetAPIValue iface.v4.name) # Get IPv4 address of the default interface - pi_ip4_addrs="$(GetAPIValue iface.v4.num_addrs 2>/dev/null)" - pi_ip4_addr="$(GetAPIValue iface.v4.addr 2>/dev/null)" + pi_ip4_addrs="$(GetAPIValue iface.v4.num_addrs)" + pi_ip4_addr="$(GetAPIValue iface.v4.addr)" if [ "${pi_ip4_addrs}" -eq 0 ]; then # No IPv4 address available pi_ip4_addr="N/A" @@ -409,8 +412,8 @@ GetNetworkInformation() { fi # Get IPv6 address of the default interface - pi_ip6_addrs="$(GetAPIValue iface.v6.num_addrs 2>/dev/null)" - pi_ip6_addr="$(GetAPIValue iface.v6.addr 2>/dev/null)" + pi_ip6_addrs="$(GetAPIValue iface.v6.num_addrs)" + pi_ip6_addr="$(GetAPIValue iface.v6.addr)" if [ "${pi_ip6_addrs}" -eq 0 ]; then # No IPv6 address available pi_ip6_addr="N/A" @@ -425,11 +428,11 @@ GetNetworkInformation() { fi # Is Pi-Hole acting as the DHCP server? - DHCP_ACTIVE="$(GetAPIValue config.dhcp_active 2>/dev/null )" + DHCP_ACTIVE="$(GetAPIValue config.dhcp_active )" if [ "${DHCP_ACTIVE}" = "true" ]; then - DHCP_START="$(GetAPIValue config.dhcp_start 2>/dev/null)" - DHCP_END="$(GetAPIValue config.dhcp_end 2>/dev/null)" + DHCP_START="$(GetAPIValue config.dhcp_start)" + DHCP_END="$(GetAPIValue config.dhcp_end)" dhcp_status="Enabled" dhcp_info=" Range: ${DHCP_START} - ${DHCP_END}" @@ -437,7 +440,7 @@ GetNetworkInformation() { dhcp_check_box=${check_box_good} # Is DHCP handling IPv6? - DHCP_IPv6="$(GetAPIValue config.dhcp_ipv6 2>/dev/null)" + DHCP_IPv6="$(GetAPIValue config.dhcp_ipv6)" if [ "${DHCP_IPv6}" = "true" ]; then dhcp_ipv6_status="Enabled" dhcp_ipv6_heatmap=${green_text} @@ -461,11 +464,11 @@ GetNetworkInformation() { fi # Get hostname - pi_hostname="$(GetAPIValue node_name 2>/dev/null)" + pi_hostname="$(GetAPIValue node_name)" full_hostname=${pi_hostname} # when PI-hole is the DHCP server, append the domain to the hostname if [ "${DHCP_ACTIVE}" = "true" ]; then - PIHOLE_DOMAIN="$(GetAPIValue config.dns_domain 2>/dev/null)" + PIHOLE_DOMAIN="$(GetAPIValue config.dns_domain)" if [ -n "${PIHOLE_DOMAIN}" ]; then count=${pi_hostname}"."${PIHOLE_DOMAIN} count=${#count} @@ -476,7 +479,7 @@ GetNetworkInformation() { fi # Get the number of configured upstream DNS servers - dns_count="$(GetAPIValue config.dns_num_upstreams 2>/dev/null)" + dns_count="$(GetAPIValue config.dns_num_upstreams)" # if there's only one DNS server if [ "${dns_count}" -eq 1 ]; then dns_information="1 server" @@ -486,7 +489,7 @@ GetNetworkInformation() { # DNSSEC - DNSSEC="$(GetAPIValue config.dns_dnssec 2>/dev/null)" + DNSSEC="$(GetAPIValue config.dns_dnssec)" if [ "${DNSSEC}" = "true" ]; then dnssec_status="Enabled" dnssec_heatmap=${green_text} @@ -496,7 +499,7 @@ GetNetworkInformation() { fi # Conditional forwarding - CONDITIONAL_FORWARDING="$(GetAPIValue config.dns_revServer_active 2>/dev/null)" + CONDITIONAL_FORWARDING="$(GetAPIValue config.dns_revServer_active)" if [ "${CONDITIONAL_FORWARDING}" = "true" ]; then conditional_forwarding_status="Enabled" conditional_forwarding_heatmap=${green_text} @@ -507,12 +510,12 @@ GetNetworkInformation() { # Default interface data (use IPv4 interface - we cannot show both and assume they are the same) iface_name="${gateway_v4_iface}" - tx_bytes="$(GetAPIValue iface.v4.tx_bytes.value 2>/dev/null)" - tx_bytes_unit="$(GetAPIValue iface.v4.tx_bytes.unit 2>/dev/null)" + tx_bytes="$(GetAPIValue iface.v4.tx_bytes.value)" + tx_bytes_unit="$(GetAPIValue iface.v4.tx_bytes.unit)" tx_bytes=$(printf "%.1f %b" "${tx_bytes}" "${tx_bytes_unit}") - rx_bytes="$(GetAPIValue iface.v4.rx_bytes.value 2>/dev/null)" - rx_bytes_unit="$(GetAPIValue iface.v4.rx_bytes.unit 2>/dev/null)" + rx_bytes="$(GetAPIValue iface.v4.rx_bytes.value)" + rx_bytes_unit="$(GetAPIValue iface.v4.rx_bytes.unit)" rx_bytes=$(printf "%.1f %b" "${rx_bytes}" "${rx_bytes_unit}") # If IPv4 and IPv6 interfaces are not the same, add a "*" to the interface @@ -540,14 +543,14 @@ GetPiholeInformation() { ftl_heatmap=${green_text} ftl_check_box=${check_box_good} # Get FTL CPU and memory usage - ftl_cpu_raw="$(GetAPIValue "%cpu" 2>/dev/null)" - ftl_mem_percentage_raw="$(GetAPIValue "%mem" 2>/dev/null)" + ftl_cpu_raw="$(GetAPIValue "%cpu")" + ftl_mem_percentage_raw="$(GetAPIValue "%mem")" ftl_cpu="$(printf "%.1f" "${ftl_cpu_raw}")%" ftl_mem_percentage="$(printf "%.1f" "${ftl_mem_percentage_raw}")%" # Get Pi-hole (blocking) status - ftl_dns_port=$(GetAPIValue config.dns_port 2>/dev/null) + ftl_dns_port=$(GetAPIValue config.dns_port) # Get FTL's current PID - ftlPID="$(GetAPIValue pid 2>/dev/null)" + ftlPID="$(GetAPIValue pid)" fi @@ -573,11 +576,11 @@ GetVersionInformation() { # Gather DOCKER version information... # returns "null" if not running Pi-hole in Docker container - DOCKER_VERSION="$(GetAPIValue version.docker.local 2>/dev/null)" + DOCKER_VERSION="$(GetAPIValue version.docker.local)" # If PADD is running inside docker, immediately return without checking for updated component versions if [ ! "${DOCKER_VERSION}" = "null" ] ; then - GITHUB_DOCKER_VERSION="$(GetAPIValue version.docker.remote 2>/dev/null)" + GITHUB_DOCKER_VERSION="$(GetAPIValue version.docker.remote)" docker_version_converted="$(VersionConverter "${DOCKER_VERSION}")" docker_version_latest_converted="$(VersionConverter "${GITHUB_DOCKER_VERSION}")" @@ -594,11 +597,11 @@ GetVersionInformation() { fi # Gather core version information... - CORE_BRANCH="$(GetAPIValue version.core.local.branch 2>/dev/null)" - CORE_VERSION="$(GetAPIValue version.core.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_CORE_VERSION="$(GetAPIValue version.core.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - CORE_HASH="$(GetAPIValue version.core.local.hash 2>/dev/null)" - GITHUB_CORE_HASH="$(GetAPIValue version.core.remote.hash 2>/dev/null)" + CORE_BRANCH="$(GetAPIValue version.core.local.branch)" + CORE_VERSION="$(GetAPIValue version.core.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_CORE_VERSION="$(GetAPIValue version.core.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + CORE_HASH="$(GetAPIValue version.core.local.hash)" + GITHUB_CORE_HASH="$(GetAPIValue version.core.remote.hash)" if [ "${CORE_BRANCH}" = "master" ]; then core_version_converted="$(VersionConverter "${CORE_VERSION}")" @@ -632,14 +635,14 @@ GetVersionInformation() { fi # Gather web version information... - WEB_VERSION="$(GetAPIValue version.web.local.version 2>/dev/null)" + WEB_VERSION="$(GetAPIValue version.web.local.version)" if [ ! "$WEB_VERSION" = "null" ]; then - WEB_BRANCH="$(GetAPIValue version.web.local.branch 2>/dev/null)" - WEB_VERSION="$(GetAPIValue version.web.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_WEB_VERSION="$(GetAPIValue version.web.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - WEB_HASH="$(GetAPIValue version.web.local.hash 2>/dev/null)" - GITHUB_WEB_HASH="$(GetAPIValue version.web.remote.hash 2>/dev/null)" + WEB_BRANCH="$(GetAPIValue version.web.local.branch)" + WEB_VERSION="$(GetAPIValue version.web.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_WEB_VERSION="$(GetAPIValue version.web.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + WEB_HASH="$(GetAPIValue version.web.local.hash)" + GITHUB_WEB_HASH="$(GetAPIValue version.web.remote.hash)" if [ "${WEB_BRANCH}" = "master" ]; then web_version_converted="$(VersionConverter "${WEB_VERSION}")" @@ -679,11 +682,11 @@ GetVersionInformation() { fi # Gather FTL version information... - FTL_BRANCH="$(GetAPIValue version.ftl.local.branch 2>/dev/null)" - FTL_VERSION="$(GetAPIValue version.ftl.local.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_FTL_VERSION="$(GetAPIValue version.ftl.remmote.version 2>/dev/null | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - FTL_HASH="$(GetAPIValue version.ftl.local.hash 2>/dev/null)" - GITHUB_FTL_HASH="$(GetAPIValue version.ftl.remote.hash 2>/dev/null)" + FTL_BRANCH="$(GetAPIValue version.ftl.local.branch)" + FTL_VERSION="$(GetAPIValue version.ftl.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_FTL_VERSION="$(GetAPIValue version.ftl.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + FTL_HASH="$(GetAPIValue version.ftl.local.hash)" + GITHUB_FTL_HASH="$(GetAPIValue version.ftl.remote.hash)" if [ "${FTL_BRANCH}" = "master" ]; then @@ -1315,7 +1318,7 @@ secretRead() { unset key unset charcount charcount=0 - while key=$(dd ibs=1 count=1 2>/dev/null); do #read one byte of input + while key=$(dd ibs=1 count=1); do #read one byte of input if [ "${key}" = "$(printf '\0' | tr -d '\0')" ] ; then # Enter - accept password break From f1c3382bdaa277704c79366e5c08dcc6542d679b Mon Sep 17 00:00:00 2001 From: RD WebDesign Date: Wed, 7 Aug 2024 22:49:37 -0300 Subject: [PATCH 65/96] Using `paths(scalars | true)` to return `null` and `false` values. We also check if the value is exactly `null` and, in this case, return the string "null", as jq would return an empty string for nulls. Signed-off-by: RD WebDesign --- padd.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/padd.sh b/padd.sh index b9cbf28..2d3e6fb 100755 --- a/padd.sh +++ b/padd.sh @@ -267,14 +267,16 @@ GetFTLData() { GetAPIData() { local api_data api_data=$(GetFTLData "padd" "$1") + # Iterate over all the leaf paths in the JSON object and creates key-value # pairs in the format "key=value". Nested objects are flattened using the dot # notation, e.g., { "a": { "b": 1 } } becomes "a.b=1". - # We have to redefine the function here, as it it is broken in jq, see - # https://github.com/jqlang/jq/issues/2872 # We cannot use leaf_paths here as it was deprecated in jq 1.6 and removed in # current master - padd_data=$(echo "$api_data" | jq -r 'def paths(node_filter): . as $dot|paths|select(. as $p|$dot|getpath($p)|node_filter|true); paths(scalars) as $p | [$p | join(".")] + [getpath($p)] | join("=")' 2>/dev/null) + # Using "paths(scalars | true)" will return null and false values. + # We also check if the value is exactly `null` and, in this case, return the + # string "null", as jq would return an empty string for nulls. + padd_data=$(echo "$api_data" | jq -r 'paths(scalars | true) as $p | [$p | join(".")] + [if getpath($p)!=null then getpath($p) else "null" end] | join("=")' 2>/dev/null) } GetAPIValue() { From 285f387fe9ef93e957f4ff2b587c6742ed249f7d Mon Sep 17 00:00:00 2001 From: yubiuser Date: Fri, 9 Aug 2024 14:41:33 +0200 Subject: [PATCH 66/96] Rename functions to clarify their use Signed-off-by: yubiuser --- padd.sh | 164 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/padd.sh b/padd.sh index 2d3e6fb..8cc8d06 100755 --- a/padd.sh +++ b/padd.sh @@ -264,9 +264,9 @@ GetFTLData() { ############################################# GETTERS ############################################## -GetAPIData() { - local api_data - api_data=$(GetFTLData "padd" "$1") +GetPADDData() { + local response + response=$(GetFTLData "padd" "$1") # Iterate over all the leaf paths in the JSON object and creates key-value # pairs in the format "key=value". Nested objects are flattened using the dot @@ -276,41 +276,41 @@ GetAPIData() { # Using "paths(scalars | true)" will return null and false values. # We also check if the value is exactly `null` and, in this case, return the # string "null", as jq would return an empty string for nulls. - padd_data=$(echo "$api_data" | jq -r 'paths(scalars | true) as $p | [$p | join(".")] + [if getpath($p)!=null then getpath($p) else "null" end] | join("=")' 2>/dev/null) + padd_data=$(echo "$response" | jq -r 'paths(scalars | true) as $p | [$p | join(".")] + [if getpath($p)!=null then getpath($p) else "null" end] | join("=")' 2>/dev/null) } -GetAPIValue() { +GetPADDValue() { echo "$padd_data" | sed -n "s/^$1=//p" 2>/dev/null } GetSummaryInformation() { - clients=$(GetAPIValue active_clients) + clients=$(GetPADDValue active_clients) - blocking_enabled=$(GetAPIValue blocking) + blocking_enabled=$(GetPADDValue blocking) - domains_being_blocked_raw=$(GetAPIValue gravity_size) + domains_being_blocked_raw=$(GetPADDValue gravity_size) domains_being_blocked=$(printf "%.f" "${domains_being_blocked_raw}") - dns_queries_today_raw=$(GetAPIValue queries.total) + dns_queries_today_raw=$(GetPADDValue queries.total) dns_queries_today=$(printf "%.f" "${dns_queries_today_raw}") - ads_blocked_today_raw=$(GetAPIValue queries.blocked) + ads_blocked_today_raw=$(GetPADDValue queries.blocked) ads_blocked_today=$(printf "%.f" "${ads_blocked_today_raw}") - ads_percentage_today_raw=$(GetAPIValue queries.percent_blocked) + ads_percentage_today_raw=$(GetPADDValue queries.percent_blocked) ads_percentage_today=$(printf "%.1f" "${ads_percentage_today_raw}") - cache_size=$(GetAPIValue cache.size) - cache_evictions=$(GetAPIValue cache.evicted) - cache_inserts=$(echo "${padd_data}"| GetAPIValue cache.inserted) + cache_size=$(GetPADDValue cache.size) + cache_evictions=$(GetPADDValue cache.evicted) + cache_inserts=$(echo "${padd_data}"| GetPADDValue cache.inserted) - latest_blocked_raw=$(GetAPIValue recent_blocked) + latest_blocked_raw=$(GetPADDValue recent_blocked) - top_blocked_raw=$(GetAPIValue top_blocked) + top_blocked_raw=$(GetPADDValue top_blocked) - top_domain_raw=$(GetAPIValue top_domain) + top_domain_raw=$(GetPADDValue top_domain) - top_client_raw=$(GetAPIValue top_client) + top_client_raw=$(GetPADDValue top_client) } GetSystemInformation() { @@ -319,14 +319,14 @@ GetSystemInformation() { # in case FTL connection is down, system_uptime_raw need to be set to 0 otherwise convertUptime() will complain system_uptime_raw=0 else - system_uptime_raw=$(GetAPIValue system.uptime) + system_uptime_raw=$(GetPADDValue system.uptime) fi # CPU temperature and unit # in case .sensors.cpu_temp returns 'null' we substitute with 0 - cpu_temp_raw=$(GetAPIValue sensors.cpu_temp) + cpu_temp_raw=$(GetPADDValue sensors.cpu_temp) cpu_temp=$(printf "%.1f" "${cpu_temp_raw}") - temp_unit=$(echo "${padd_data}" | GetAPIValue sensors.unit) + temp_unit=$(echo "${padd_data}" | GetPADDValue sensors.unit) # Temp + Unit if [ "${temp_unit}" = "C" ]; then @@ -364,22 +364,22 @@ GetSystemInformation() { fi # CPU, load, heatmap - core_count=$(GetAPIValue system.cpu.nprocs) - cpu_load_1=$(printf %.2f "$(GetAPIValue system.cpu.load.0)") - cpu_load_5=$(printf %.2f "$(GetAPIValue system.cpu.load.1)") - cpu_load_15=$(printf %.2f "$(GetAPIValue system.cpu.load.2)") + core_count=$(GetPADDValue system.cpu.nprocs) + cpu_load_1=$(printf %.2f "$(GetPADDValue system.cpu.load.0)") + cpu_load_5=$(printf %.2f "$(GetPADDValue system.cpu.load.1)") + cpu_load_15=$(printf %.2f "$(GetPADDValue system.cpu.load.2)") cpu_load_1_heatmap=$(HeatmapGenerator "${cpu_load_1}" "${core_count}") cpu_load_5_heatmap=$(HeatmapGenerator "${cpu_load_5}" "${core_count}") cpu_load_15_heatmap=$(HeatmapGenerator "${cpu_load_15}" "${core_count}") - cpu_percent=$(printf %.1f "$(GetAPIValue system.cpu.load.percent.0)") + cpu_percent=$(printf %.1f "$(GetPADDValue system.cpu.load.percent.0)") # Memory use, heatmap and bar - memory_percent_raw="$(GetAPIValue system.memory.ram.%used)" + memory_percent_raw="$(GetPADDValue system.memory.ram.%used)" memory_percent=$(printf %.1f "${memory_percent_raw}") memory_heatmap="$(HeatmapGenerator "${memory_percent}")" # Get device model - sys_model="$(GetAPIValue host_model)" + sys_model="$(GetPADDValue host_model)" # DOCKER_VERSION is set during GetVersionInformation, so this needs to run first during startup if [ ! "${DOCKER_VERSION}" = "null" ]; then @@ -397,12 +397,12 @@ GetSystemInformation() { } GetNetworkInformation() { - gateway_v4_iface=$(GetAPIValue iface.v4.name) - gateway_v6_iface=$(GetAPIValue iface.v4.name) + gateway_v4_iface=$(GetPADDValue iface.v4.name) + gateway_v6_iface=$(GetPADDValue iface.v4.name) # Get IPv4 address of the default interface - pi_ip4_addrs="$(GetAPIValue iface.v4.num_addrs)" - pi_ip4_addr="$(GetAPIValue iface.v4.addr)" + pi_ip4_addrs="$(GetPADDValue iface.v4.num_addrs)" + pi_ip4_addr="$(GetPADDValue iface.v4.addr)" if [ "${pi_ip4_addrs}" -eq 0 ]; then # No IPv4 address available pi_ip4_addr="N/A" @@ -414,8 +414,8 @@ GetNetworkInformation() { fi # Get IPv6 address of the default interface - pi_ip6_addrs="$(GetAPIValue iface.v6.num_addrs)" - pi_ip6_addr="$(GetAPIValue iface.v6.addr)" + pi_ip6_addrs="$(GetPADDValue iface.v6.num_addrs)" + pi_ip6_addr="$(GetPADDValue iface.v6.addr)" if [ "${pi_ip6_addrs}" -eq 0 ]; then # No IPv6 address available pi_ip6_addr="N/A" @@ -430,11 +430,11 @@ GetNetworkInformation() { fi # Is Pi-Hole acting as the DHCP server? - DHCP_ACTIVE="$(GetAPIValue config.dhcp_active )" + DHCP_ACTIVE="$(GetPADDValue config.dhcp_active )" if [ "${DHCP_ACTIVE}" = "true" ]; then - DHCP_START="$(GetAPIValue config.dhcp_start)" - DHCP_END="$(GetAPIValue config.dhcp_end)" + DHCP_START="$(GetPADDValue config.dhcp_start)" + DHCP_END="$(GetPADDValue config.dhcp_end)" dhcp_status="Enabled" dhcp_info=" Range: ${DHCP_START} - ${DHCP_END}" @@ -442,7 +442,7 @@ GetNetworkInformation() { dhcp_check_box=${check_box_good} # Is DHCP handling IPv6? - DHCP_IPv6="$(GetAPIValue config.dhcp_ipv6)" + DHCP_IPv6="$(GetPADDValue config.dhcp_ipv6)" if [ "${DHCP_IPv6}" = "true" ]; then dhcp_ipv6_status="Enabled" dhcp_ipv6_heatmap=${green_text} @@ -458,7 +458,7 @@ GetNetworkInformation() { dhcp_check_box=${check_box_bad} # Display the gateway address if DHCP is disabled - GATEWAY="$(GetAPIValue iface.v4.gw_addr | head -n 1)" + GATEWAY="$(GetPADDValue iface.v4.gw_addr | head -n 1)" dhcp_info=" Router: ${GATEWAY}" dhcp_ipv6_status="N/A" dhcp_ipv6_heatmap=${yellow_text} @@ -466,11 +466,11 @@ GetNetworkInformation() { fi # Get hostname - pi_hostname="$(GetAPIValue node_name)" + pi_hostname="$(GetPADDValue node_name)" full_hostname=${pi_hostname} # when PI-hole is the DHCP server, append the domain to the hostname if [ "${DHCP_ACTIVE}" = "true" ]; then - PIHOLE_DOMAIN="$(GetAPIValue config.dns_domain)" + PIHOLE_DOMAIN="$(GetPADDValue config.dns_domain)" if [ -n "${PIHOLE_DOMAIN}" ]; then count=${pi_hostname}"."${PIHOLE_DOMAIN} count=${#count} @@ -481,7 +481,7 @@ GetNetworkInformation() { fi # Get the number of configured upstream DNS servers - dns_count="$(GetAPIValue config.dns_num_upstreams)" + dns_count="$(GetPADDValue config.dns_num_upstreams)" # if there's only one DNS server if [ "${dns_count}" -eq 1 ]; then dns_information="1 server" @@ -491,7 +491,7 @@ GetNetworkInformation() { # DNSSEC - DNSSEC="$(GetAPIValue config.dns_dnssec)" + DNSSEC="$(GetPADDValue config.dns_dnssec)" if [ "${DNSSEC}" = "true" ]; then dnssec_status="Enabled" dnssec_heatmap=${green_text} @@ -501,7 +501,7 @@ GetNetworkInformation() { fi # Conditional forwarding - CONDITIONAL_FORWARDING="$(GetAPIValue config.dns_revServer_active)" + CONDITIONAL_FORWARDING="$(GetPADDValue config.dns_revServer_active)" if [ "${CONDITIONAL_FORWARDING}" = "true" ]; then conditional_forwarding_status="Enabled" conditional_forwarding_heatmap=${green_text} @@ -512,12 +512,12 @@ GetNetworkInformation() { # Default interface data (use IPv4 interface - we cannot show both and assume they are the same) iface_name="${gateway_v4_iface}" - tx_bytes="$(GetAPIValue iface.v4.tx_bytes.value)" - tx_bytes_unit="$(GetAPIValue iface.v4.tx_bytes.unit)" + tx_bytes="$(GetPADDValue iface.v4.tx_bytes.value)" + tx_bytes_unit="$(GetPADDValue iface.v4.tx_bytes.unit)" tx_bytes=$(printf "%.1f %b" "${tx_bytes}" "${tx_bytes_unit}") - rx_bytes="$(GetAPIValue iface.v4.rx_bytes.value)" - rx_bytes_unit="$(GetAPIValue iface.v4.rx_bytes.unit)" + rx_bytes="$(GetPADDValue iface.v4.rx_bytes.value)" + rx_bytes_unit="$(GetPADDValue iface.v4.rx_bytes.unit)" rx_bytes=$(printf "%.1f %b" "${rx_bytes}" "${rx_bytes_unit}") # If IPv4 and IPv6 interfaces are not the same, add a "*" to the interface @@ -545,14 +545,14 @@ GetPiholeInformation() { ftl_heatmap=${green_text} ftl_check_box=${check_box_good} # Get FTL CPU and memory usage - ftl_cpu_raw="$(GetAPIValue "%cpu")" - ftl_mem_percentage_raw="$(GetAPIValue "%mem")" + ftl_cpu_raw="$(GetPADDValue "%cpu")" + ftl_mem_percentage_raw="$(GetPADDValue "%mem")" ftl_cpu="$(printf "%.1f" "${ftl_cpu_raw}")%" ftl_mem_percentage="$(printf "%.1f" "${ftl_mem_percentage_raw}")%" # Get Pi-hole (blocking) status - ftl_dns_port=$(GetAPIValue config.dns_port) + ftl_dns_port=$(GetPADDValue config.dns_port) # Get FTL's current PID - ftlPID="$(GetAPIValue pid)" + ftlPID="$(GetPADDValue pid)" fi @@ -578,11 +578,11 @@ GetVersionInformation() { # Gather DOCKER version information... # returns "null" if not running Pi-hole in Docker container - DOCKER_VERSION="$(GetAPIValue version.docker.local)" + DOCKER_VERSION="$(GetPADDValue version.docker.local)" # If PADD is running inside docker, immediately return without checking for updated component versions if [ ! "${DOCKER_VERSION}" = "null" ] ; then - GITHUB_DOCKER_VERSION="$(GetAPIValue version.docker.remote)" + GITHUB_DOCKER_VERSION="$(GetPADDValue version.docker.remote)" docker_version_converted="$(VersionConverter "${DOCKER_VERSION}")" docker_version_latest_converted="$(VersionConverter "${GITHUB_DOCKER_VERSION}")" @@ -599,11 +599,11 @@ GetVersionInformation() { fi # Gather core version information... - CORE_BRANCH="$(GetAPIValue version.core.local.branch)" - CORE_VERSION="$(GetAPIValue version.core.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_CORE_VERSION="$(GetAPIValue version.core.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - CORE_HASH="$(GetAPIValue version.core.local.hash)" - GITHUB_CORE_HASH="$(GetAPIValue version.core.remote.hash)" + CORE_BRANCH="$(GetPADDValue version.core.local.branch)" + CORE_VERSION="$(GetPADDValue version.core.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_CORE_VERSION="$(GetPADDValue version.core.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + CORE_HASH="$(GetPADDValue version.core.local.hash)" + GITHUB_CORE_HASH="$(GetPADDValue version.core.remote.hash)" if [ "${CORE_BRANCH}" = "master" ]; then core_version_converted="$(VersionConverter "${CORE_VERSION}")" @@ -637,14 +637,14 @@ GetVersionInformation() { fi # Gather web version information... - WEB_VERSION="$(GetAPIValue version.web.local.version)" + WEB_VERSION="$(GetPADDValue version.web.local.version)" if [ ! "$WEB_VERSION" = "null" ]; then - WEB_BRANCH="$(GetAPIValue version.web.local.branch)" - WEB_VERSION="$(GetAPIValue version.web.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_WEB_VERSION="$(GetAPIValue version.web.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - WEB_HASH="$(GetAPIValue version.web.local.hash)" - GITHUB_WEB_HASH="$(GetAPIValue version.web.remote.hash)" + WEB_BRANCH="$(GetPADDValue version.web.local.branch)" + WEB_VERSION="$(GetPADDValue version.web.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_WEB_VERSION="$(GetPADDValue version.web.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + WEB_HASH="$(GetPADDValue version.web.local.hash)" + GITHUB_WEB_HASH="$(GetPADDValue version.web.remote.hash)" if [ "${WEB_BRANCH}" = "master" ]; then web_version_converted="$(VersionConverter "${WEB_VERSION}")" @@ -684,11 +684,11 @@ GetVersionInformation() { fi # Gather FTL version information... - FTL_BRANCH="$(GetAPIValue version.ftl.local.branch)" - FTL_VERSION="$(GetAPIValue version.ftl.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - GITHUB_FTL_VERSION="$(GetAPIValue version.ftl.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" - FTL_HASH="$(GetAPIValue version.ftl.local.hash)" - GITHUB_FTL_HASH="$(GetAPIValue version.ftl.remote.hash)" + FTL_BRANCH="$(GetPADDValue version.ftl.local.branch)" + FTL_VERSION="$(GetPADDValue version.ftl.local.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + GITHUB_FTL_VERSION="$(GetPADDValue version.ftl.remmote.version | tr -d '[:alpha:]' | awk -F '-' '{printf $1}')" + FTL_HASH="$(GetPADDValue version.ftl.local.hash)" + GITHUB_FTL_HASH="$(GetPADDValue version.ftl.remote.hash)" if [ "${FTL_BRANCH}" = "master" ]; then @@ -1376,7 +1376,7 @@ OutputJSON() { printf "%b" "Establishing connection with FTL...\n" LoginAPI - GetAPIData + GetPADDData GetSummaryInformation printf "%b" "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today},\"clients\": ${clients}}" } @@ -1440,8 +1440,8 @@ StartupRoutine(){ moveXOffset; printf "%b" " [■·········] 10%\r" - # Request API data - GetAPIData + # Request PADD data + GetPADDData # Check for updates moveXOffset; printf "%b" " [■■········] 20%\r" @@ -1471,9 +1471,9 @@ StartupRoutine(){ moveXOffset; printf "%b" "Establishing connection with FTL...\n" LoginAPI - # Request API data - moveXOffset; echo "- Requesting API information..." - GetAPIData + # Request PADD data + moveXOffset; echo "- Requesting PADD information..." + GetPADDData # Get our information for the first time moveXOffset; echo "- Gathering version info." @@ -1510,9 +1510,9 @@ StartupRoutine(){ moveXOffset; printf "%b" "Establishing connection with FTL...\n" LoginAPI - # Request API data - moveXOffset; echo "- Requesting API information..." - GetAPIData + # Request PADD data + moveXOffset; echo "- Requesting PADD information..." + GetPADDData # Get our information for the first time moveXOffset; echo "- Gathering version information..." @@ -1583,15 +1583,15 @@ NormalPADD() { Authenticate fi - # Request API data + # Request PADD data if [ $((now - LastCheckFullInformation)) -ge 30 ]; then - GetAPIData + GetPADDData GetNetworkInformation GetVersionInformation LastCheckFullInformation="${now}" else # Request only a subset of the data - GetAPIData "?full=false" + GetPADDData "?full=false" fi # Get uptime, CPU load, temp, etc. every 5 seconds From d8c6f3344faf75690699d0ed94636c51fec591de Mon Sep 17 00:00:00 2001 From: yubiuser Date: Fri, 9 Aug 2024 14:42:13 +0200 Subject: [PATCH 67/96] Re add necessary 2>/dev/null Signed-off-by: yubiuser --- padd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/padd.sh b/padd.sh index 8cc8d06..30f766e 100755 --- a/padd.sh +++ b/padd.sh @@ -1320,7 +1320,7 @@ secretRead() { unset key unset charcount charcount=0 - while key=$(dd ibs=1 count=1); do #read one byte of input + while key=$(dd ibs=1 count=1 2>/dev/null); do #read one byte of input if [ "${key}" = "$(printf '\0' | tr -d '\0')" ] ; then # Enter - accept password break From e18403b9228ff6e0a32aa63ead6661fc11aceb1c Mon Sep 17 00:00:00 2001 From: yubiuser Date: Fri, 9 Aug 2024 15:33:42 +0200 Subject: [PATCH 68/96] Suppress curl errors Signed-off-by: yubiuser --- padd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/padd.sh b/padd.sh index 30f766e..d4ac2c3 100755 --- a/padd.sh +++ b/padd.sh @@ -243,7 +243,7 @@ Authenticate() { GetFTLData() { local response # get the data from querying the API as well as the http status code - response=$(curl -skS -w "%{http_code}" -X GET "${API_URL}$1$2" -H "Accept: application/json" -H "sid: ${SID}" ) + response=$(curl -sk -w "%{http_code}" -X GET "${API_URL}$1$2" -H "Accept: application/json" -H "sid: ${SID}" ) # status are the last 3 characters status=$(printf %s "${response#"${response%???}"}") From 573d36ff20d8eceb3e161219caa35c321218d13a Mon Sep 17 00:00:00 2001 From: yubiuser Date: Fri, 9 Aug 2024 15:37:57 +0200 Subject: [PATCH 69/96] padd_data is a global variable Signed-off-by: yubiuser --- padd.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/padd.sh b/padd.sh index d4ac2c3..b5b0c9c 100755 --- a/padd.sh +++ b/padd.sh @@ -21,6 +21,9 @@ padd_version="v4.0.0" LastCheckPADDInformation=$(date +%s) LastCheckFullInformation=$(date +%s) +# padd_data holds the data returned by FTL's /padd endpoint globally +padd_data="" + # COLORS CSI="$(printf '\033')[" # Control Sequence Introducer red_text="${CSI}91m" # Red @@ -242,6 +245,9 @@ Authenticate() { GetFTLData() { local response + local data + local status + # get the data from querying the API as well as the http status code response=$(curl -sk -w "%{http_code}" -X GET "${API_URL}$1$2" -H "Accept: application/json" -H "sid: ${SID}" ) From ed3143f79aa299e0845fc19d9eb44d5852db2270 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Fri, 9 Aug 2024 15:41:44 +0200 Subject: [PATCH 70/96] Propagate API response errors upstream Signed-off-by: yubiuser --- padd.sh | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/padd.sh b/padd.sh index b5b0c9c..fb9339a 100755 --- a/padd.sh +++ b/padd.sh @@ -274,15 +274,23 @@ GetPADDData() { local response response=$(GetFTLData "padd" "$1") - # Iterate over all the leaf paths in the JSON object and creates key-value - # pairs in the format "key=value". Nested objects are flattened using the dot - # notation, e.g., { "a": { "b": 1 } } becomes "a.b=1". - # We cannot use leaf_paths here as it was deprecated in jq 1.6 and removed in - # current master - # Using "paths(scalars | true)" will return null and false values. - # We also check if the value is exactly `null` and, in this case, return the - # string "null", as jq would return an empty string for nulls. - padd_data=$(echo "$response" | jq -r 'paths(scalars | true) as $p | [$p | join(".")] + [if getpath($p)!=null then getpath($p) else "null" end] | join("=")' 2>/dev/null) + if [ "${response}" = 000 ]; then + # connection lost + padd_data="000" + elif [ "${response}" = 401 ]; then + # unauthorized + padd_data="401" + else + # Iterate over all the leaf paths in the JSON object and creates key-value + # pairs in the format "key=value". Nested objects are flattened using the dot + # notation, e.g., { "a": { "b": 1 } } becomes "a.b=1". + # We cannot use leaf_paths here as it was deprecated in jq 1.6 and removed in + # current master + # Using "paths(scalars | true)" will return null and false values. + # We also check if the value is exactly `null` and, in this case, return the + # string "null", as jq would return an empty string for nulls. + padd_data=$(echo "$response" | jq -r 'paths(scalars | true) as $p | [$p | join(".")] + [if getpath($p)!=null then getpath($p) else "null" end] | join("=")' 2>/dev/null) + fi } GetPADDValue() { From 97006b0681ad38d541c7b4406e88d82bb9361849 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Fri, 9 Aug 2024 21:05:59 +0200 Subject: [PATCH 71/96] Fix --version command Signed-off-by: yubiuser --- padd.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/padd.sh b/padd.sh index fb9339a..1f1b64a 100755 --- a/padd.sh +++ b/padd.sh @@ -1413,6 +1413,7 @@ ShowVersion() { printf "%b" "Establishing connection with FTL...\n" LoginAPI + GetPADDData GetVersionInformation GetPADDInformation if [ -z "${padd_version_latest}" ]; then From 51fde8aa88719920995c533e1444e808f6945b50 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Fri, 9 Aug 2024 22:44:14 +0200 Subject: [PATCH 72/96] Skip all the processing if FTL is down Signed-off-by: yubiuser --- padd.sh | 156 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 124 insertions(+), 32 deletions(-) diff --git a/padd.sh b/padd.sh index 1f1b64a..813dba1 100755 --- a/padd.sh +++ b/padd.sh @@ -20,6 +20,7 @@ padd_version="v4.0.0" # LastChecks LastCheckPADDInformation=$(date +%s) LastCheckFullInformation=$(date +%s) +LastCheckNetworkInformation=$(date +%s) # padd_data holds the data returned by FTL's /padd endpoint globally padd_data="" @@ -298,6 +299,24 @@ GetPADDValue() { } GetSummaryInformation() { + if [ "${connection_down_flag}" = true ]; then + clients="N/A" + blocking_enabled="N/A" + domains_being_blocked="N/A" + dns_queries_today="N/A" + ads_blocked_today="N/A" + ads_percentage_today="N/A" + cache_size="N/A" + cache_evictions="N/A" + cache_inserts="N/A" + latest_blocked_raw="N/A" + top_blocked_raw="N/A" + top_domain_raw="N/A" + top_client_raw="N/A" + return + fi + + clients=$(GetPADDValue active_clients) blocking_enabled=$(GetPADDValue blocking) @@ -328,16 +347,31 @@ GetSummaryInformation() { } GetSystemInformation() { - # System uptime - if [ "${padd_data}" = 000 ]; then - # in case FTL connection is down, system_uptime_raw need to be set to 0 otherwise convertUptime() will complain - system_uptime_raw=0 - else - system_uptime_raw=$(GetPADDValue system.uptime) + + if [ "${connection_down_flag}" = true ]; then + system_uptime_raw=0 + temperature="N/A" + temp_heatmap=${reset_text} + + cpu_load_1="N/A" + cpu_load_5="N/A" + cpu_load_15="N/A" + cpu_load_1_heatmap=${reset_text} + cpu_load_5_heatmap=${reset_text} + cpu_load_15_heatmap=${reset_text} + cpu_percent=0 + + memory_percent=0 + memory_heatmap=${reset_text} + + sys_model="N/A" + return fi + # System uptime + system_uptime_raw=$(GetPADDValue system.uptime) + # CPU temperature and unit - # in case .sensors.cpu_temp returns 'null' we substitute with 0 cpu_temp_raw=$(GetPADDValue sensors.cpu_temp) cpu_temp=$(printf "%.1f" "${cpu_temp_raw}") temp_unit=$(echo "${padd_data}" | GetPADDValue sensors.unit) @@ -411,6 +445,36 @@ GetSystemInformation() { } GetNetworkInformation() { + if [ "${connection_down_flag}" = true ]; then + iface_name="N/A" + pi_ip4_addr="N/A" + pi_ip6_addr="N/A" + ipv6_check_box=${check_box_question} + + dhcp_status="N/A" + dhcp_heatmap=${reset_text} + dhcp_info="" + dhcp_ipv6_status="N/A" + dhcp_ipv6_heatmap=${reset_text} + dhcp_ipv6_check_box=${check_box_question} + + pi_hostname="N/A" + full_hostname="N/A" + + dns_count="N/A" + dns_information="N/A" + + dnssec_status="N/A" + dnssec_heatmap=${reset_text} + + conditional_forwarding_status="N/A" + conditional_forwarding_heatmap=${reset_text} + + tx_bytes="N/A" + rx_bytes="N/A" + return + fi + gateway_v4_iface=$(GetPADDValue iface.v4.name) gateway_v6_iface=$(GetPADDValue iface.v4.name) @@ -544,17 +608,21 @@ GetNetworkInformation() { } GetPiholeInformation() { - # If FTL is not running (sysinfo is 000), set all variables to "not running" - connection_down_flag=false - if [ "${padd_data}" = "000" ]; then - ftl_status="No connection" - ftl_heatmap=${red_text} - ftl_check_box=${check_box_bad} - # set flag to change the status message in SetStatusMessage() - connection_down_flag=true - ftl_cpu="N/A" - ftl_mem_percentage="N/A" - else + if [ "${connection_down_flag}" = true ]; then + ftl_status="No connection" + ftl_heatmap=${red_text} + ftl_check_box=${check_box_bad} + ftl_cpu="N/A" + ftl_mem_percentage="N/A" + dns_status="DNS offline" + dns_heatmap=${red_text} + dns_check_box=${check_box_bad} + ftlPID="N/A" + dns_down_flag=true + + return + fi + ftl_status="Running" ftl_heatmap=${green_text} ftl_check_box=${check_box_good} @@ -567,13 +635,12 @@ GetPiholeInformation() { ftl_dns_port=$(GetPADDValue config.dns_port) # Get FTL's current PID ftlPID="$(GetPADDValue pid)" - fi # ${ftl_dns_port} == 0 DNS server part of dnsmasq disabled dns_down_flag=false - if [ "${ftl_dns_port}" = 0 ] || [ "${ftl_status}" = "No connection" ]; then + if [ "${ftl_dns_port}" = 0 ]; then dns_status="DNS offline" dns_heatmap=${red_text} dns_check_box=${check_box_bad} @@ -587,6 +654,16 @@ fi } GetVersionInformation() { + if [ "${connection_down_flag}" = true ]; then + DOCKER_VERSION=null + CORE_VERSION="N/A" + WEB_VERSION="N/A" + FTL_VERSION="N/A" + core_version_heatmap=${reset_text} + web_version_heatmap=${reset_text} + ftl_version_heatmap=${reset_text} + return + fi out_of_date_flag=false @@ -861,7 +938,7 @@ SetStatusMessage() { full_status=${full_status_dns_down} mega_status=${mega_status_dns_down} - elif [ "${blocking_enabled}" = "false" ]; then + elif [ "${blocking_enabled}" = "disabled" ]; then # Check if blocking status is disabled pico_status=${pico_status_off} mini_status=${mini_status_off} @@ -877,7 +954,7 @@ SetStatusMessage() { full_status=${full_status_update} mega_status=${mega_status_update} - elif [ "${blocking_enabled}" = "true" ]; then + elif [ "${blocking_enabled}" = "enabled" ]; then # if we reach this point and blocking is enabled, everything is fine pico_status=${pico_status_ok} mini_status=${mini_status_ok} @@ -1601,23 +1678,38 @@ NormalPADD() { # Request PADD data if [ $((now - LastCheckFullInformation)) -ge 30 ]; then GetPADDData - GetNetworkInformation - GetVersionInformation LastCheckFullInformation="${now}" else # Request only a subset of the data GetPADDData "?full=false" fi - # Get uptime, CPU load, temp, etc. every 5 seconds - GetSystemInformation - GetSummaryInformation - GetPiholeInformation + connection_down_flag=false + # If the connection was lost, set connection_down_flag + if [ "${padd_data}" = "000" ]; then + connection_down_flag=true + GetSystemInformation + GetSummaryInformation + GetPiholeInformation + GetNetworkInformation + GetVersionInformation + else + # Get uptime, CPU load, temp, etc. every 5 seconds + GetSystemInformation + GetSummaryInformation + GetPiholeInformation - # Get PADD version information every 24hours - if [ $((now - LastCheckPADDInformation)) -ge 86400 ]; then - GetPADDInformation - LastCheckPADDInformation="${now}" + if [ $((now - LastCheckNetworkInformation)) -ge 30 ]; then + GetNetworkInformation + GetVersionInformation + LastCheckNetworkInformation="${now}" + fi + + # Get PADD version information every 24hours + if [ $((now - LastCheckPADDInformation)) -ge 86400 ]; then + GetPADDInformation + LastCheckPADDInformation="${now}" + fi fi done From 09e33964f638e7a7a9ac577e42340425ff1bdafd Mon Sep 17 00:00:00 2001 From: yubiuser Date: Fri, 9 Aug 2024 22:53:04 +0200 Subject: [PATCH 73/96] Set --connect-timeout for curl connections Signed-off-by: yubiuser --- padd.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/padd.sh b/padd.sh index 813dba1..df6dccd 100755 --- a/padd.sh +++ b/padd.sh @@ -137,7 +137,7 @@ TestAPIAvailability() { API_URL="${API_URL#\"}" # Test if the API is available at this URL - availabilityResponse=$(curl -skS -o /dev/null -w "%{http_code}" "${API_URL}auth") + availabilityResponse=$(curl --connect-timeout 2 -skS -o /dev/null -w "%{http_code}" "${API_URL}auth") # Test if http status code was 200 (OK) or 401 (authentication required) if [ ! "${availabilityResponse}" = 200 ] && [ ! "${availabilityResponse}" = 401 ]; then @@ -217,7 +217,7 @@ DeleteSession() { # SID is not null (successful authenthication only), delete the session if [ "${validSession}" = true ] && [ ! "${SID}" = null ]; then # Try to delete the session. Omit the output, but get the http status code - deleteResponse=$(curl -skS -o /dev/null -w "%{http_code}" -X DELETE "${API_URL}auth" -H "Accept: application/json" -H "sid: ${SID}") + deleteResponse=$(curl --connect-timeout 2 -skS -o /dev/null -w "%{http_code}" -X DELETE "${API_URL}auth" -H "Accept: application/json" -H "sid: ${SID}") printf "\n\n" case "${deleteResponse}" in @@ -232,7 +232,7 @@ DeleteSession() { } Authenticate() { - sessionResponse="$(curl -skS -X POST "${API_URL}auth" --user-agent "PADD ${padd_version}" --data "{\"password\":\"${password}\"}" )" + sessionResponse="$(curl --connect-timeout 2 -skS -X POST "${API_URL}auth" --user-agent "PADD ${padd_version}" --data "{\"password\":\"${password}\"}" )" if [ -z "${sessionResponse}" ]; then moveXOffset; echo "No response from FTL server. Please check connectivity and use the options to set the API URL" @@ -250,7 +250,7 @@ GetFTLData() { local status # get the data from querying the API as well as the http status code - response=$(curl -sk -w "%{http_code}" -X GET "${API_URL}$1$2" -H "Accept: application/json" -H "sid: ${SID}" ) + response=$(curl --connect-timeout 2 -sk -w "%{http_code}" -X GET "${API_URL}$1$2" -H "Accept: application/json" -H "sid: ${SID}" ) # status are the last 3 characters status=$(printf %s "${response#"${response%???}"}") @@ -822,7 +822,7 @@ GetPADDInformation() { fi # PADD version information... - padd_version_latest="$(curl --silent https://api.github.com/repos/pi-hole/PADD/releases/latest | grep '"tag_name":' | awk -F \" '{print $4}')" + padd_version_latest="$(curl --connect-timeout 5 --silent https://api.github.com/repos/pi-hole/PADD/releases/latest | grep '"tag_name":' | awk -F \" '{print $4}')" # is PADD up-to-date? padd_out_of_date_flag=false if [ -z "${padd_version_latest}" ]; then @@ -1733,7 +1733,7 @@ Update() { echo "${check_box_info} Downloading PADD update ..." - if curl -sSL https://install.padd.sh -o "${padd_script_path}" > /dev/null 2>&1; then + if curl --connect-timeout 5 -sSL https://install.padd.sh -o "${padd_script_path}" > /dev/null 2>&1; then echo "${check_box_good} ... done. Restart PADD for the update to take effect" else echo "${check_box_bad} Cannot download PADD update" From 0440ade345deb0a3ae6efa1c42d6e2293879f642 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Fri, 9 Aug 2024 23:20:13 +0200 Subject: [PATCH 74/96] Require all API data after connection is re-established Signed-off-by: yubiuser --- padd.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/padd.sh b/padd.sh index df6dccd..cfb3ead 100755 --- a/padd.sh +++ b/padd.sh @@ -1675,8 +1675,8 @@ NormalPADD() { Authenticate fi - # Request PADD data - if [ $((now - LastCheckFullInformation)) -ge 30 ]; then + # Request PADD data after 30 seconds or if the connection was lost + if [ $((now - LastCheckFullInformation)) -ge 30 ] || [ "${connection_down_flag}" = true ] ; then GetPADDData LastCheckFullInformation="${now}" else @@ -1693,16 +1693,19 @@ NormalPADD() { GetPiholeInformation GetNetworkInformation GetVersionInformation + # set flag to update network information in the next loop in case the connection is re-established + get_network_information_requried=true else # Get uptime, CPU load, temp, etc. every 5 seconds GetSystemInformation GetSummaryInformation GetPiholeInformation - if [ $((now - LastCheckNetworkInformation)) -ge 30 ]; then + if [ $((now - LastCheckNetworkInformation)) -ge 30 ] || [ "${get_network_information_requried}" = true ]; then GetNetworkInformation GetVersionInformation LastCheckNetworkInformation="${now}" + get_network_information_requried=false fi # Get PADD version information every 24hours From 9bfb33869ba855adb34808db29c515e9378d91f2 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Thu, 26 Sep 2024 22:43:49 +0200 Subject: [PATCH 75/96] Fix CPU load Signed-off-by: yubiuser --- padd.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/padd.sh b/padd.sh index cfb3ead..1cef213 100755 --- a/padd.sh +++ b/padd.sh @@ -413,9 +413,9 @@ GetSystemInformation() { # CPU, load, heatmap core_count=$(GetPADDValue system.cpu.nprocs) - cpu_load_1=$(printf %.2f "$(GetPADDValue system.cpu.load.0)") - cpu_load_5=$(printf %.2f "$(GetPADDValue system.cpu.load.1)") - cpu_load_15=$(printf %.2f "$(GetPADDValue system.cpu.load.2)") + cpu_load_1=$(printf %.2f "$(GetPADDValue system.cpu.load.raw.[0])") + cpu_load_5=$(printf %.2f "$(GetPADDValue system.cpu.load.raw.[1])") + cpu_load_15=$(printf %.2f "$(GetPADDValue system.cpu.load.raw.[2])") cpu_load_1_heatmap=$(HeatmapGenerator "${cpu_load_1}" "${core_count}") cpu_load_5_heatmap=$(HeatmapGenerator "${cpu_load_5}" "${core_count}") cpu_load_15_heatmap=$(HeatmapGenerator "${cpu_load_15}" "${core_count}") From f7c88ee4fb9b72a77e34ab375c5a8dab3db94a2d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 10:37:19 +0000 Subject: [PATCH 76/96] Bump actions/checkout from 4.1.7 to 4.2.0 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.7 to 4.2.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.1.7...v4.2.0) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/codespell.yml | 2 +- .github/workflows/editorconfig-checker.yml | 2 +- .github/workflows/stale.yml | 2 +- .github/workflows/sync-back-to-dev.yml | 2 +- .github/workflows/version_bump.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 693eda0..1e8eab3 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 - name: Spell-Checking uses: codespell-project/actions-codespell@master diff --git a/.github/workflows/editorconfig-checker.yml b/.github/workflows/editorconfig-checker.yml index 5cd18d4..2cbc4ac 100644 --- a/.github/workflows/editorconfig-checker.yml +++ b/.github/workflows/editorconfig-checker.yml @@ -9,6 +9,6 @@ jobs: name: editorconfig-checker runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.7 + - uses: actions/checkout@v4.2.0 - uses: editorconfig-checker/action-editorconfig-checker@main # current tag v1.0.0 is really out-of-date - run: editorconfig-checker diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 6f93787..ad28295 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 - name: Remove 'stale' label run: gh issue edit ${{ github.event.issue.number }} --remove-label ${{ env.stale_label }} env: diff --git a/.github/workflows/sync-back-to-dev.yml b/.github/workflows/sync-back-to-dev.yml index db88f65..bea8908 100644 --- a/.github/workflows/sync-back-to-dev.yml +++ b/.github/workflows/sync-back-to-dev.yml @@ -11,7 +11,7 @@ jobs: name: Syncing branches steps: - name: Checkout - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 - name: Opening pull request run: gh pr create -B development -H master --title 'Sync master back into development' --body 'Created by Github action' --label 'Internal' env: diff --git a/.github/workflows/version_bump.yml b/.github/workflows/version_bump.yml index 14c6e83..f082d57 100644 --- a/.github/workflows/version_bump.yml +++ b/.github/workflows/version_bump.yml @@ -20,7 +20,7 @@ jobs: [[ -z ${LATEST_TAG} ]] && echo "Error: LATEST_TAG is empty, aborting" && exit 1 - name: Checkout code - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.0 with: ref: 'development' From 384af25645345ecf1dfb4b82c31621e2f666681d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Oct 2024 10:52:36 +0000 Subject: [PATCH 77/96] Bump actions/checkout from 4.2.0 to 4.2.1 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.0 to 4.2.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.2.0...v4.2.1) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codespell.yml | 2 +- .github/workflows/editorconfig-checker.yml | 2 +- .github/workflows/stale.yml | 2 +- .github/workflows/sync-back-to-dev.yml | 2 +- .github/workflows/version_bump.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 1e8eab3..726cdbe 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.2.0 + uses: actions/checkout@v4.2.1 - name: Spell-Checking uses: codespell-project/actions-codespell@master diff --git a/.github/workflows/editorconfig-checker.yml b/.github/workflows/editorconfig-checker.yml index 2cbc4ac..b32b5af 100644 --- a/.github/workflows/editorconfig-checker.yml +++ b/.github/workflows/editorconfig-checker.yml @@ -9,6 +9,6 @@ jobs: name: editorconfig-checker runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.2.0 + - uses: actions/checkout@v4.2.1 - uses: editorconfig-checker/action-editorconfig-checker@main # current tag v1.0.0 is really out-of-date - run: editorconfig-checker diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index ad28295..dc8fdc4 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4.2.0 + uses: actions/checkout@v4.2.1 - name: Remove 'stale' label run: gh issue edit ${{ github.event.issue.number }} --remove-label ${{ env.stale_label }} env: diff --git a/.github/workflows/sync-back-to-dev.yml b/.github/workflows/sync-back-to-dev.yml index bea8908..4cf5c5b 100644 --- a/.github/workflows/sync-back-to-dev.yml +++ b/.github/workflows/sync-back-to-dev.yml @@ -11,7 +11,7 @@ jobs: name: Syncing branches steps: - name: Checkout - uses: actions/checkout@v4.2.0 + uses: actions/checkout@v4.2.1 - name: Opening pull request run: gh pr create -B development -H master --title 'Sync master back into development' --body 'Created by Github action' --label 'Internal' env: diff --git a/.github/workflows/version_bump.yml b/.github/workflows/version_bump.yml index f082d57..622f200 100644 --- a/.github/workflows/version_bump.yml +++ b/.github/workflows/version_bump.yml @@ -20,7 +20,7 @@ jobs: [[ -z ${LATEST_TAG} ]] && echo "Error: LATEST_TAG is empty, aborting" && exit 1 - name: Checkout code - uses: actions/checkout@v4.2.0 + uses: actions/checkout@v4.2.1 with: ref: 'development' From 8bcf9f4b45bc46b7a163d4b81ae30230c1751e74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 10:38:01 +0000 Subject: [PATCH 78/96] Bump actions/checkout from 4.2.1 to 4.2.2 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.1 to 4.2.2. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.2.1...v4.2.2) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codespell.yml | 2 +- .github/workflows/editorconfig-checker.yml | 2 +- .github/workflows/stale.yml | 2 +- .github/workflows/sync-back-to-dev.yml | 2 +- .github/workflows/version_bump.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 726cdbe..f81d0e5 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4.2.1 + uses: actions/checkout@v4.2.2 - name: Spell-Checking uses: codespell-project/actions-codespell@master diff --git a/.github/workflows/editorconfig-checker.yml b/.github/workflows/editorconfig-checker.yml index b32b5af..8f104c2 100644 --- a/.github/workflows/editorconfig-checker.yml +++ b/.github/workflows/editorconfig-checker.yml @@ -9,6 +9,6 @@ jobs: name: editorconfig-checker runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.2.1 + - uses: actions/checkout@v4.2.2 - uses: editorconfig-checker/action-editorconfig-checker@main # current tag v1.0.0 is really out-of-date - run: editorconfig-checker diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index dc8fdc4..9889992 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4.2.1 + uses: actions/checkout@v4.2.2 - name: Remove 'stale' label run: gh issue edit ${{ github.event.issue.number }} --remove-label ${{ env.stale_label }} env: diff --git a/.github/workflows/sync-back-to-dev.yml b/.github/workflows/sync-back-to-dev.yml index 4cf5c5b..d9c7ed1 100644 --- a/.github/workflows/sync-back-to-dev.yml +++ b/.github/workflows/sync-back-to-dev.yml @@ -11,7 +11,7 @@ jobs: name: Syncing branches steps: - name: Checkout - uses: actions/checkout@v4.2.1 + uses: actions/checkout@v4.2.2 - name: Opening pull request run: gh pr create -B development -H master --title 'Sync master back into development' --body 'Created by Github action' --label 'Internal' env: diff --git a/.github/workflows/version_bump.yml b/.github/workflows/version_bump.yml index 622f200..8aeecab 100644 --- a/.github/workflows/version_bump.yml +++ b/.github/workflows/version_bump.yml @@ -20,7 +20,7 @@ jobs: [[ -z ${LATEST_TAG} ]] && echo "Error: LATEST_TAG is empty, aborting" && exit 1 - name: Checkout code - uses: actions/checkout@v4.2.1 + uses: actions/checkout@v4.2.2 with: ref: 'development' From 689e602effce9dd74fb232708c35f9856312d65b Mon Sep 17 00:00:00 2001 From: yubiuser Date: Sun, 22 Dec 2024 23:42:12 +0100 Subject: [PATCH 79/96] Speedup response handling Signed-off-by: yubiuser --- padd.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/padd.sh b/padd.sh index 1cef213..f4524da 100755 --- a/padd.sh +++ b/padd.sh @@ -253,7 +253,8 @@ GetFTLData() { response=$(curl --connect-timeout 2 -sk -w "%{http_code}" -X GET "${API_URL}$1$2" -H "Accept: application/json" -H "sid: ${SID}" ) # status are the last 3 characters - status=$(printf %s "${response#"${response%???}"}") + # not using ${response#"${response%???}"}" here because it's extremely slow on big responses + status=$(printf "%s" "${response}" | tail -c 3) # data is everything from response without the last 3 characters data=$(printf %s "${response%???}") From b73487016b4e59e8cbde32bd920d86392c1966fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Jan 2025 10:39:09 +0000 Subject: [PATCH 80/96] Bump eps1lon/actions-label-merge-conflict from 3.0.2 to 3.0.3 Bumps [eps1lon/actions-label-merge-conflict](https://github.com/eps1lon/actions-label-merge-conflict) from 3.0.2 to 3.0.3. - [Release notes](https://github.com/eps1lon/actions-label-merge-conflict/releases) - [Changelog](https://github.com/eps1lon/actions-label-merge-conflict/blob/main/CHANGELOG.md) - [Commits](https://github.com/eps1lon/actions-label-merge-conflict/compare/v3.0.2...v3.0.3) --- updated-dependencies: - dependency-name: eps1lon/actions-label-merge-conflict dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/merge-conflict.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/merge-conflict.yml b/.github/workflows/merge-conflict.yml index c24de2c..ea30b65 100644 --- a/.github/workflows/merge-conflict.yml +++ b/.github/workflows/merge-conflict.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check if PRs are have merge conflicts - uses: eps1lon/actions-label-merge-conflict@v3.0.2 + uses: eps1lon/actions-label-merge-conflict@v3.0.3 with: dirtyLabel: "Merge Conflict" repoToken: "${{ secrets.GITHUB_TOKEN }}" From ab940d0eec8674f111cd39433950fec0d2479ada Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 25 Jan 2025 10:12:33 +0000 Subject: [PATCH 81/96] Bump actions/stale from 9.0.0 to 9.1.0 Bumps [actions/stale](https://github.com/actions/stale) from 9.0.0 to 9.1.0. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v9.0.0...v9.1.0) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/stale.yml | 2 +- .github/workflows/stale_pr.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 9889992..558223f 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -17,7 +17,7 @@ jobs: issues: write steps: - - uses: actions/stale@v9.0.0 + - uses: actions/stale@v9.1.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} days-before-stale: 30 diff --git a/.github/workflows/stale_pr.yml b/.github/workflows/stale_pr.yml index 171c903..2441271 100644 --- a/.github/workflows/stale_pr.yml +++ b/.github/workflows/stale_pr.yml @@ -17,7 +17,7 @@ jobs: pull-requests: write steps: - - uses: actions/stale@v9.0.0 + - uses: actions/stale@v9.1.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} # Do not automatically mark PR/issue as stale From 8e2a93cdae27b34c0ce6add23d27e5f92d46fe19 Mon Sep 17 00:00:00 2001 From: RD WebDesign Date: Tue, 11 Feb 2025 23:16:24 -0300 Subject: [PATCH 82/96] Change the color for some disabled elements to avoid confusion Using blue color because not every disabled setting means an error. Signed-off-by: RD WebDesign --- padd.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/padd.sh b/padd.sh index f4524da..c952581 100755 --- a/padd.sh +++ b/padd.sh @@ -528,12 +528,12 @@ GetNetworkInformation() { dhcp_ipv6_check_box=${check_box_good} else dhcp_ipv6_status="Disabled" - dhcp_ipv6_heatmap=${red_text} + dhcp_ipv6_heatmap=${blue_text} dhcp_ipv6_check_box=${check_box_bad} fi else dhcp_status="Disabled" - dhcp_heatmap=${red_text} + dhcp_heatmap=${blue_text} dhcp_check_box=${check_box_bad} # Display the gateway address if DHCP is disabled @@ -576,7 +576,7 @@ GetNetworkInformation() { dnssec_heatmap=${green_text} else dnssec_status="Disabled" - dnssec_heatmap=${red_text} + dnssec_heatmap=${blue_text} fi # Conditional forwarding @@ -586,7 +586,7 @@ GetNetworkInformation() { conditional_forwarding_heatmap=${green_text} else conditional_forwarding_status="Disabled" - conditional_forwarding_heatmap=${red_text} + conditional_forwarding_heatmap=${blue_text} fi # Default interface data (use IPv4 interface - we cannot show both and assume they are the same) From 74b3670ca6a06c2b161ed4b2c8bfb31f220a958c Mon Sep 17 00:00:00 2001 From: RD WebDesign Date: Tue, 11 Feb 2025 23:45:39 -0300 Subject: [PATCH 83/96] Also use a new blue box to represent disabled items Signed-off-by: RD WebDesign --- padd.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/padd.sh b/padd.sh index c952581..7e694a0 100755 --- a/padd.sh +++ b/padd.sh @@ -44,6 +44,7 @@ dim_text="${CSI}2m" # CHECK BOXES check_box_good="[${green_text}✓${reset_text}]" # Good check_box_bad="[${red_text}✗${reset_text}]" # Bad +check_box_disabled="[${blue_text}-${reset_text}]" # Disabled, but not an error check_box_question="[${yellow_text}?${reset_text}]" # Question / ? check_box_info="[${yellow_text}i${reset_text}]" # Info / i @@ -529,12 +530,12 @@ GetNetworkInformation() { else dhcp_ipv6_status="Disabled" dhcp_ipv6_heatmap=${blue_text} - dhcp_ipv6_check_box=${check_box_bad} + dhcp_ipv6_check_box=${check_box_disabled} fi else dhcp_status="Disabled" dhcp_heatmap=${blue_text} - dhcp_check_box=${check_box_bad} + dhcp_check_box=${check_box_disabled} # Display the gateway address if DHCP is disabled GATEWAY="$(GetPADDValue iface.v4.gw_addr | head -n 1)" From 7d1a0b02ff4af5b84f1cd77f9f59d2e0b4cf6709 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Wed, 12 Feb 2025 14:01:51 +0100 Subject: [PATCH 84/96] Improve DHCP and IPv6 info Signed-off-by: yubiuser --- padd.sh | 63 ++++++++++++++++++++++++--------------------------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/padd.sh b/padd.sh index 7e694a0..021a343 100755 --- a/padd.sh +++ b/padd.sh @@ -451,14 +451,16 @@ GetNetworkInformation() { iface_name="N/A" pi_ip4_addr="N/A" pi_ip6_addr="N/A" + ipv6_status="N/A" + ipv6_heatmap=${reset_text} ipv6_check_box=${check_box_question} dhcp_status="N/A" dhcp_heatmap=${reset_text} - dhcp_info="" + dhcp_range="N/A" + dhcp_range_heatmap=${reset_text} dhcp_ipv6_status="N/A" dhcp_ipv6_heatmap=${reset_text} - dhcp_ipv6_check_box=${check_box_question} pi_hostname="N/A" full_hostname="N/A" @@ -500,13 +502,19 @@ GetNetworkInformation() { # No IPv6 address available pi_ip6_addr="N/A" ipv6_check_box=${check_box_bad} + ipv6_status="Disabled" + ipv6_heatmap=${red_text} elif [ "${pi_ip6_addrs}" -eq 1 ]; then # One IPv6 address available ipv6_check_box=${check_box_good} + ipv6_status="Enabled" + ipv6_heatmap=${green_text} else # More than one IPv6 address available pi_ip6_addr="${pi_ip6_addr}+" ipv6_check_box=${check_box_good} + ipv6_status="Enabled" + ipv6_heatmap=${green_text} fi # Is Pi-Hole acting as the DHCP server? @@ -517,7 +525,8 @@ GetNetworkInformation() { DHCP_END="$(GetPADDValue config.dhcp_end)" dhcp_status="Enabled" - dhcp_info=" Range: ${DHCP_START} - ${DHCP_END}" + dhcp_range="${DHCP_START} - ${DHCP_END}" + dhcp_range_heatmap=${reset_text} dhcp_heatmap=${green_text} dhcp_check_box=${check_box_good} @@ -526,23 +535,19 @@ GetNetworkInformation() { if [ "${DHCP_IPv6}" = "true" ]; then dhcp_ipv6_status="Enabled" dhcp_ipv6_heatmap=${green_text} - dhcp_ipv6_check_box=${check_box_good} else dhcp_ipv6_status="Disabled" dhcp_ipv6_heatmap=${blue_text} - dhcp_ipv6_check_box=${check_box_disabled} fi else dhcp_status="Disabled" dhcp_heatmap=${blue_text} dhcp_check_box=${check_box_disabled} + dhcp_range="N/A" - # Display the gateway address if DHCP is disabled - GATEWAY="$(GetPADDValue iface.v4.gw_addr | head -n 1)" - dhcp_info=" Router: ${GATEWAY}" dhcp_ipv6_status="N/A" + dhcp_range_heatmap=${yellow_text} dhcp_ipv6_heatmap=${yellow_text} - dhcp_ipv6_check_box=${check_box_question} fi # Get hostname @@ -1022,7 +1027,7 @@ PrintDashboard() { moveXOffset; printf "%s${clear_line}\n" "${bold_text}NETWORK ============${reset_text}" moveXOffset; printf "%s${clear_line}\n" " Hst: ${pi_hostname}" moveXOffset; printf "%s${clear_line}\n" " IP: ${pi_ip4_addr}" - moveXOffset; printf "%s${clear_line}\n" " DHCP ${dhcp_check_box} IPv6 ${dhcp_ipv6_check_box}" + moveXOffset; printf "%s${clear_line}\n" " IPv6 ${ipv6_check_box} DHCP ${dhcp_check_box}" moveXOffset; printf "%s${clear_line}\n" "${bold_text}CPU ================${reset_text}" moveXOffset; printf "%s${clear_line}" " [${cpu_load_1_heatmap}${cpu_bar}${reset_text}] ${cpu_percent}%" elif [ "$1" = "nano" ]; then @@ -1035,7 +1040,7 @@ PrintDashboard() { moveXOffset; printf "%s${clear_line}\n" "${bold_text}NETWORK ================${reset_text}" moveXOffset; printf "%s${clear_line}\n" " Host: ${pi_hostname}" moveXOffset; printf "%s${clear_line}\n" " IP: ${pi_ip4_addr}" - moveXOffset; printf "%s${clear_line}\n" " DHCP: ${dhcp_check_box} IPv6: ${dhcp_ipv6_check_box}" + moveXOffset; printf "%s${clear_line}\n" " IPv6: ${ipv6_check_box} DHCP: ${dhcp_check_box}" moveXOffset; printf "%s${clear_line}\n" "${bold_text}SYSTEM =================${reset_text}" moveXOffset; printf "%s${clear_line}\n" " Up: ${system_uptime}" moveXOffset; printf "%s${clear_line}" " CPU: [${cpu_load_1_heatmap}${cpu_bar}${reset_text}] ${cpu_percent}%" @@ -1044,7 +1049,7 @@ PrintDashboard() { moveXOffset; printf "%s${clear_line}\n" "µ${padd_text} ${mini_status}" moveXOffset; printf "%s${clear_line}\n" "" moveXOffset; printf "%s${clear_line}\n" "${bold_text}PI-HOLE ======================${reset_text}" - moveXOffset; printf "%s${clear_line}\n" " DNS: ${dns_check_box} FTL: ${ftl_check_box}" + moveXOffset; printf "%s${clear_line}\n" " DNS: ${dns_check_box} FTL: ${ftl_check_box}" moveXOffset; printf "%s${clear_line}\n" "${bold_text}STATS ========================${reset_text}" moveXOffset; printf "%s${clear_line}\n" " Blckng: ${domains_being_blocked} domains" moveXOffset; printf "%s${clear_line}\n" " Piholed: [${ads_blocked_bar}] ${ads_percentage_today}%" @@ -1052,7 +1057,7 @@ PrintDashboard() { moveXOffset; printf "%s${clear_line}\n" "${bold_text}NETWORK ======================${reset_text}" moveXOffset; printf "%s${clear_line}\n" " Host: ${full_hostname}" moveXOffset; printf "%s${clear_line}\n" " IP: ${pi_ip4_addr}" - moveXOffset; printf "%s${clear_line}\n" " DHCP: ${dhcp_check_box} IPv6: ${dhcp_ipv6_check_box}" + moveXOffset; printf "%s${clear_line}\n" " IPv6: ${ipv6_check_box} DHCP: ${dhcp_check_box}" moveXOffset; printf "%s${clear_line}\n" "${bold_text}SYSTEM =======================${reset_text}" moveXOffset; printf "%s${clear_line}\n" " Uptime: ${system_uptime}" moveXOffset; printf "%s${clear_line}\n" " Load: [${cpu_load_1_heatmap}${cpu_bar}${reset_text}] ${cpu_percent}%" @@ -1068,16 +1073,12 @@ PrintDashboard() { moveXOffset; printf " %-9s[%-20s] %-5s${clear_line}\n" "Piholed:" "${ads_blocked_bar}" "${ads_percentage_today}%" moveXOffset; printf " %-9s%-29s${clear_line}\n" "Piholed:" "${ads_blocked_today} out of ${dns_queries_today}" moveXOffset; printf " %-9s%-29s${clear_line}\n" "Latest:" "${latest_blocked}" - if [ "${DHCP_ACTIVE}" != "true" ]; then - moveXOffset; printf " %-9s%-29s${clear_line}\n" "Top Ad:" "${top_blocked}" - fi moveXOffset; printf "%s${clear_line}\n" "${bold_text}NETWORK ================================${reset_text}" moveXOffset; printf " %-9s%-16s%-5s%-9s${clear_line}\n" "Host:" "${full_hostname}" "DNS:" "${dns_information}" moveXOffset; printf " %-9s%s${clear_line}\n" "IP:" "${pi_ip4_addr} (${iface_name})" + moveXOffset; printf " %-9s${ipv6_heatmap}%-10s${reset_text} %-8s${dhcp_heatmap}%-10s${reset_text}${clear_line}\n" "IPv6:" "${ipv6_status}" "DHCP:" "${dhcp_status}" + moveXOffset; printf " %-9s%-4s%-12s%-4s%-5s${clear_line}\n" "Traffic:" "TX:" "${tx_bytes}" "RX:" "${rx_bytes}" - if [ "${DHCP_ACTIVE}" = "true" ]; then - moveXOffset; printf " %-9s${dhcp_heatmap}%-10s${reset_text} %-9s${dhcp_ipv6_heatmap}%-10s${reset_text}${clear_line}\n" "DHCP:" "${dhcp_status}" "IPv6:" ${dhcp_ipv6_status} - fi moveXOffset; printf "%s${clear_line}\n" "${bold_text}SYSTEM =================================${reset_text}" moveXOffset; printf " %-9s%-29s${clear_line}\n" "Uptime:" "${system_uptime}" moveXOffset; printf "%s${clear_line}\n" " Load: [${cpu_load_1_heatmap}${cpu_bar}${reset_text}] ${cpu_percent}%" @@ -1094,18 +1095,12 @@ PrintDashboard() { moveXOffset; printf " %-10s%-39s${clear_line}\n" "Pi-holed:" "${ads_blocked_today} out of ${dns_queries_today}" moveXOffset; printf " %-10s%-39s${clear_line}\n" "Latest:" "${latest_blocked}" moveXOffset; printf " %-10s%-39s${clear_line}\n" "Top Ad:" "${top_blocked}" - if [ "${DHCP_ACTIVE}" != "true" ]; then - moveXOffset; printf " %-10s%-39s${clear_line}\n" "Top Dmn:" "${top_domain}" - moveXOffset; printf " %-10s%-39s${clear_line}\n" "Top Clnt:" "${top_client}" - fi moveXOffset; printf "%s${clear_line}\n" "${bold_text}NETWORK =============================================${reset_text}" moveXOffset; printf " %-10s%-16s %-8s%-16s${clear_line}\n" "Hostname:" "${full_hostname}" "IP: " "${pi_ip4_addr}" moveXOffset; printf " %-10s%-16s %-4s%-7s %-4s%-5s${clear_line}\n" "Interfce:" "${iface_name}" "TX:" "${tx_bytes}" "RX:" "${rx_bytes}" moveXOffset; printf " %-10s%-16s %-8s${dnssec_heatmap}%-16s${reset_text}${clear_line}\n" "DNS:" "${dns_information}" "DNSSEC:" "${dnssec_status}" - if [ "${DHCP_ACTIVE}" = "true" ]; then - moveXOffset; printf " %-10s${dhcp_heatmap}%-16s${reset_text} %-8s${dhcp_ipv6_heatmap}%-10s${reset_text}${clear_line}\n" "DHCP:" "${dhcp_status}" "IPv6:" ${dhcp_ipv6_status} - moveXOffset; printf "%s${clear_line}\n" "${dhcp_info}" - fi + moveXOffset; printf " %-10s%s${clear_line}\n" "IPv6:" "${pi_ip6_addr}" + moveXOffset; printf " %-10s%-15s%-4s${dhcp_range_heatmap}%-36s${reset_text}${clear_line}\n" "DHCP:" "${dhcp_check_box}" "Rng" "${dhcp_range}" moveXOffset; printf "%s${clear_line}\n" "${bold_text}SYSTEM ==============================================${reset_text}" moveXOffset; printf " %-10s%-29s${clear_line}\n" "Uptime:" "${system_uptime}" moveXOffset; printf " %-10s${temp_heatmap}%-17s${reset_text} %-8s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-4s${reset_text}${clear_line}\n" "CPU Temp:" "${temperature}" "Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" @@ -1131,18 +1126,12 @@ PrintDashboard() { moveXOffset; printf " %-10s%-49s${clear_line}\n" "Pi-holed:" "${ads_blocked_today} out of ${dns_queries_today} queries" moveXOffset; printf " %-10s%-39s${clear_line}\n" "Latest:" "${latest_blocked}" moveXOffset; printf " %-10s%-39s${clear_line}\n" "Top Ad:" "${top_blocked}" - if [ "${DHCP_ACTIVE}" != "true" ]; then - moveXOffset; printf " %-10s%-39s${clear_line}\n" "Top Dmn:" "${top_domain}" - moveXOffset; printf " %-10s%-39s${clear_line}\n" "Top Clnt:" "${top_client}" - fi moveXOffset; printf "%s${clear_line}\n" "${bold_text}NETWORK ====================================================${reset_text}" - moveXOffset; printf " %-10s%-15s %-4s%-17s%-6s%s${clear_line}\n" "Hostname:" "${full_hostname}" "IP:" "${pi_ip4_addr}" "IPv6:" "${ipv6_check_box}" + moveXOffset; printf " %-10s%-15s %-4s%-17s${clear_line}\n" "Hostname:" "${full_hostname}" "IP:" "${pi_ip4_addr}" moveXOffset; printf " %-10s%-15s %-4s%-17s%-4s%s${clear_line}\n" "Interfce:" "${iface_name}" "TX:" "${tx_bytes}" "RX:" "${rx_bytes}" + moveXOffset; printf " %-10s%s${clear_line}\n" "IPv6:" "${pi_ip6_addr}" moveXOffset; printf " %-10s%-15s %-10s${dnssec_heatmap}%-19s${reset_text}${clear_line}\n" "DNS:" "${dns_information}" "DNSSEC:" "${dnssec_status}" - if [ "${DHCP_ACTIVE}" = "true" ]; then - moveXOffset; printf " %-10s${dhcp_heatmap}%-15s${reset_text} %-10s${dhcp_ipv6_heatmap}%-19s${reset_text}${clear_line}\n" "DHCP:" "${dhcp_status}" "IPv6:" ${dhcp_ipv6_status} - moveXOffset; printf "%s${clear_line}\n" "${dhcp_info}" - fi + moveXOffset; printf " %-10s%-16s%-6s${dhcp_range_heatmap}%-36s${reset_text}${clear_line}\n" "DHCP:" "${dhcp_check_box}" "Range" "${dhcp_range}" moveXOffset; printf "%s${clear_line}\n" "${bold_text}SYSTEM =====================================================${reset_text}" moveXOffset; printf " %-10s%-39s${clear_line}\n" "Uptime:" "${system_uptime}" moveXOffset; printf " %-10s${temp_heatmap}%-21s${reset_text}%-10s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-4s${reset_text}${clear_line}\n" "CPU Temp:" "${temperature}" "CPU Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" @@ -1170,7 +1159,7 @@ PrintDashboard() { moveXOffset; printf "%s${clear_line}\n" "${bold_text}DNS ==========================DHCP==============================================${reset_text}" moveXOffset; printf " %-10s%-19s %-6s${dhcp_heatmap}%-19s${reset_text}${clear_line}\n" "Servers:" "${dns_information}" "DHCP:" "${dhcp_status}" moveXOffset; printf " %-10s${dnssec_heatmap}%-19s${reset_text} %-10s${dhcp_ipv6_heatmap}%-9s${reset_text}${clear_line}\n" "DNSSEC:" "${dnssec_status}" "IPv6 Spt:" "${dhcp_ipv6_status}" - moveXOffset; printf " %-10s${conditional_forwarding_heatmap}%-19s${reset_text}%s${clear_line}\n" "CdFwding:" "${conditional_forwarding_status}" "${dhcp_info}" + moveXOffset; printf " %-10s${conditional_forwarding_heatmap}%-20s${reset_text}%-6s${dhcp_range_heatmap}%-36s${reset_text}${clear_line}\n" "CdFwding:" "${conditional_forwarding_status}" "Range" "${dhcp_range}" moveXOffset; printf "%s${clear_line}\n" "${bold_text}SYSTEM =========================================================================${reset_text}" moveXOffset; printf " %-10s%-39s${clear_line}\n" "Device:" "${sys_model}" moveXOffset; printf " %-10s%-39s %-10s[${memory_heatmap}%-10s${reset_text}] %-6s${clear_line}\n" "Uptime:" "${system_uptime}" "Memory:" "${memory_bar}" "${memory_percent}%" From e54e7030e2da360fe7b8fd99084abd933c577a65 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Wed, 12 Feb 2025 14:09:23 +0100 Subject: [PATCH 85/96] Fix startup sequence on mini Signed-off-by: yubiuser --- padd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/padd.sh b/padd.sh index 021a343..bbf72cd 100755 --- a/padd.sh +++ b/padd.sh @@ -1573,7 +1573,7 @@ StartupRoutine(){ moveXOffset; echo " - Docker Tag ${DOCKER_VERSION}" else moveXOffset; echo " - Core $CORE_VERSION, Web $WEB_VERSION" - moveXOffset; echo " - FTL $FTL_VERSION, PADD ${padd_data}_version" + moveXOffset; echo " - FTL $FTL_VERSION, PADD ${padd_version}" fi else From d7517afb178ae3ac36b699ac3d8eda22eab0a22c Mon Sep 17 00:00:00 2001 From: yubiuser Date: Wed, 12 Feb 2025 14:16:23 +0100 Subject: [PATCH 86/96] Clear the screen once on startup Signed-off-by: yubiuser --- padd.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/padd.sh b/padd.sh index bbf72cd..f52034b 100755 --- a/padd.sh +++ b/padd.sh @@ -1632,6 +1632,10 @@ NormalPADD() { # Trap the window resize signal (handle window resize events) trap 'TerminalResize' WINCH + + # Clear the screen once on startup to remove overflow from the startup routine + printf '\033[2J' + while true; do # Generate output that depends on the terminal size From d1b93720440aad8ac430c64e42ae0ec79db1158b Mon Sep 17 00:00:00 2001 From: yubiuser Date: Wed, 12 Feb 2025 21:25:03 +0100 Subject: [PATCH 87/96] Disabled IPv6 is not an error Signed-off-by: yubiuser --- padd.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/padd.sh b/padd.sh index f52034b..49bf52c 100755 --- a/padd.sh +++ b/padd.sh @@ -501,9 +501,9 @@ GetNetworkInformation() { if [ "${pi_ip6_addrs}" -eq 0 ]; then # No IPv6 address available pi_ip6_addr="N/A" - ipv6_check_box=${check_box_bad} + ipv6_check_box=${check_box_disabled} ipv6_status="Disabled" - ipv6_heatmap=${red_text} + ipv6_heatmap=${blue_text} elif [ "${pi_ip6_addrs}" -eq 1 ]; then # One IPv6 address available ipv6_check_box=${check_box_good} From 64e4927141e0ff28b2a8e043a6dc75ba230f59a3 Mon Sep 17 00:00:00 2001 From: Michael Woolweaver Date: Thu, 13 Feb 2025 10:54:27 -0600 Subject: [PATCH 88/96] remove duplicate text at end of line in DisplayHelp() Signed-off-by: Michael Woolweaver --- padd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/padd.sh b/padd.sh index 49bf52c..8b7e6fd 100755 --- a/padd.sh +++ b/padd.sh @@ -1757,7 +1757,7 @@ DisplayHelp() { ::: ::: --server domain or IP of your Pi-hole (default: localhost) ::: --secret your Pi-hole's password, required to access the API -::: -j, --json output stats as JSON formatted string and exit and exit +::: -j, --json output stats as JSON formatted string and exit ::: -u, --update update to the latest version ::: -v, --version show PADD version info ::: -h, --help display this help text From fd778f46b301ead909d882d7b2982cf8554e7640 Mon Sep 17 00:00:00 2001 From: Michael Woolweaver Date: Sat, 15 Feb 2025 17:12:43 -0600 Subject: [PATCH 89/96] move Wiki to README.md Co-authored-by: yubiuser Signed-off-by: Michael Woolweaver --- README.md | 157 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 110 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 1e3fca9..839b538 100644 --- a/README.md +++ b/README.md @@ -7,68 +7,131 @@ PADD (formerly Chronometer2) is a more expansive version of the original chronom ***Note:** PADD has been adopted by the Pi-hole team, thanks to JPMCK for creating this helpful tool! ## Setup PADD -*More in-depth information about setting up PADD can be found in this repo’s [wiki](https://github.com/pi-hole/PADD/wiki/Setup).* - Get a copy of PADD by running: - -```bash -cd ~ -wget -O padd.sh https://install.padd.sh -``` -or -```bash -cd ~ -curl -sSL https://install.padd.sh -o padd.sh -``` + ```bash + cd ~ + wget -O padd.sh https://install.padd.sh + ``` + or + ```bash + cd ~ + curl -sSL https://install.padd.sh -o padd.sh + ``` - Make PADD executable by running + ```bash + sudo chmod +x padd.sh + ``` -```bash -sudo chmod +x padd.sh -``` +## Using PADD -- Set PADD to auto run by adding the following to the end of `~/.bashrc`: +### PADD on Pi-hole machine -```bash -# Run PADD -# If we’re on the PiTFT screen (ssh is xterm) -if [ "$TERM" == "linux" ] ; then - while : - do - ./padd.sh - sleep 1 - done -fi -``` +- Just run + ```bash + ./padd.sh + ``` -One line version +### PADD from other machine +With PADD v4.0.0 and Pi-hole v6 it is also possible to run PADD from a machine that is not running Pi-hole -```bash -cd ~ ; echo "if [ \"\$TERM\" == \"linux\" ] ; then\n while :\n do\n ./padd.sh\n sleep 1\n done\nfi" | tee ~/.bashrc -a -``` +- without 2FA enabled + ```bash + ./padd.sh --server --secret + ``` -- Reboot your Pi-Hole by running `sudo reboot`. PADD should now run when your Pi-Hole has completed booting. +- with 2FA enabled + ```bash + ./padd.sh --server --secret --2fa <2fa> + ``` + +### PADD with Pi-hole in a Docker Container +- If you're running Pi-hole in the official Docker Container, `padd.sh` is pre-installed and named `padd`. It can be used with the following command: + ```bash + docker exec -it padd [padd_options] + ``` + +### PADD on PiTFT screen +_Instructions for how to setup PiTFT screen can be found [here](https://learn.adafruit.com/adafruit-pitft-3-dot-5-touch-screen-for-raspberry-pi/easy-install-2)_ + +- Set PADD to auto run on the PiTFT screen by adding the following to the end of `~/.bashrc`: + ```bash + # Run PADD + # If we’re on the PiTFT screen (ssh is xterm) + if [ "$TERM" == "linux" ] ; then + while : + do + ./padd.sh + sleep 1 + done + fi + ``` + + One line version + ```bash + cd ~ ; echo "if [ \"\$TERM\" == \"linux\" ] ; then\n while :\n do\n ./padd.sh\n sleep 1\n done\nfi" | tee ~/.bashrc -a + ``` + +- Reboot your Pi-Hole by running `sudo reboot`. PADD should now run on PiTFT Screen when your Pi-Hole has completed booting. + +#### (Optional) Put the PiTFT Display to Sleep at Night +_If you don't want your PiTFT on all night when you are asleep, you can put it to sleep! (Note: __these instructions only apply to a PiTFT__.)_ +- To do so, edit cron as root (`sudo crontab -e`) and add the following: + ```bash + # PiTFT+ SLEEPY TIME + # Turn off the PiTFT+ at midnight + 00 00 * * * sh -c 'echo "0" > /sys/class/backlight/soc\:backlight/brightness' + # Turn on the PiTFT+ at 8:00 am + 00 08 * * * sh -c 'echo "1" > /sys/class/backlight/soc\:backlight/brightness' + ``` ## Updating PADD - Simply run - -```bash -./padd.sh -u -``` - + ```bash + ./padd.sh -u + ``` - or run the same commands you used to install + ```bash + cd ~ + wget -O padd.sh https://install.padd.sh + ``` + or + ```bash + cd ~ + curl -sSL https://install.padd.sh -o padd.sh + ``` -```bash -cd ~ -wget -O padd.sh https://install.padd.sh -``` -```bash -cd ~ -curl -sSL https://install.padd.sh -o padd.sh -``` +## Sizes +PADD will display on screens that anywhere from 20x10 characters to over 80x26 characters. -## Running Pi-hole in a Docker Container -If you're running Pi-hole in the official Docker Container, `padd.sh` is pre-installed and named `padd`. It can be used with the following command: +As your screen gets smaller, you’ll be presented with less information… however, you’ll always get the most important details: +- The status of your Pi-hole (is it online, in need of an update?), +- How many ads have been blocked, +- Your hostname and IP, and +- Your CPU’s current load. + +It will also run in the following modes (shown further below): +- Pico: 20x10 characters +- Nano: 24x12 characters +- Micro: 30x16 characters +- Mini: 40x18 characters +- Tiny: 53x20 characters +- Slim: 60x21 characters +- Regular: 60x22 characters (takes up the entire screen on a 3.5" Adafruit PiTFT using the Terminal font at 8x14.) +- Mega: 80x26 characters + +### Sizing Your PADD +How PADD will display on your screen depends on the size of the screen in *characters*, not *pixels*! PADD doesn’t care if it is running on a 5k Retina display on your $5,000 iMac Pro or on a $5 display you bought on eBay. + +If you want to change how PADD displays on a small display attached to your Raspberry Pi, use ```bash -docker exec -it padd [padd_options] +sudo dpkg-reconfigure console-setup ``` +to configure your font settings to an ideal size for you. + +If you want to change how PADD displays through a terminal emulator (PuTTY, Terminal.app, iTerm2, etc.), resize your window or play with font sizes in your app of choice. + +### The Sizes + +![PADD Sizes GIF](https://github.com/pi-hole/graphics/blob/master/PADD/PADDsizes.gif) From c2150537646405c37aa2cdf1193c434331ba9c71 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Tue, 18 Feb 2025 21:06:15 +0100 Subject: [PATCH 90/96] Add note about authentication Signed-off-by: yubiuser --- README.md | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 839b538..3dad3b6 100644 --- a/README.md +++ b/README.md @@ -9,17 +9,21 @@ PADD (formerly Chronometer2) is a more expansive version of the original chronom ## Setup PADD - Get a copy of PADD by running: + ```bash cd ~ wget -O padd.sh https://install.padd.sh ``` + or + ```bash cd ~ curl -sSL https://install.padd.sh -o padd.sh ``` - Make PADD executable by running + ```bash sudo chmod +x padd.sh ``` @@ -29,33 +33,54 @@ PADD (formerly Chronometer2) is a more expansive version of the original chronom ### PADD on Pi-hole machine - Just run + ```bash ./padd.sh ``` ### PADD from other machine + With PADD v4.0.0 and Pi-hole v6 it is also possible to run PADD from a machine that is not running Pi-hole -- without 2FA enabled ```bash - ./padd.sh --server --secret + ./padd.sh --server + ``` + +### Authentication + +Pi-hole v6 uses a completely new API with a new authentication mechanism + +If you run PADD on the same machine as Pi-hole, it's possible to bypass authentication when your local user is member of the `pihole` group (specifically, if you can access `/etc/pihole/cli_password). +For details see [https://github.com/pi-hole/FTL/pull/1999](https://github.com/pi-hole/FTL/pull/1999) + +If this is not the case, PADD will ask you for your password and (if configured) your two factor authentication token. You can also pass those as arguments + +- password only + + ```bash + ./padd.sh --secret ``` - with 2FA enabled + ```bash - ./padd.sh --server --secret --2fa <2fa> + ./padd.sh --secret --2fa <2fa> ``` ### PADD with Pi-hole in a Docker Container + - If you're running Pi-hole in the official Docker Container, `padd.sh` is pre-installed and named `padd`. It can be used with the following command: + ```bash docker exec -it padd [padd_options] ``` ### PADD on PiTFT screen + _Instructions for how to setup PiTFT screen can be found [here](https://learn.adafruit.com/adafruit-pitft-3-dot-5-touch-screen-for-raspberry-pi/easy-install-2)_ - Set PADD to auto run on the PiTFT screen by adding the following to the end of `~/.bashrc`: + ```bash # Run PADD # If we’re on the PiTFT screen (ssh is xterm) @@ -69,6 +94,7 @@ _Instructions for how to setup PiTFT screen can be found [here](https://learn.ad ``` One line version + ```bash cd ~ ; echo "if [ \"\$TERM\" == \"linux\" ] ; then\n while :\n do\n ./padd.sh\n sleep 1\n done\nfi" | tee ~/.bashrc -a ``` @@ -76,8 +102,11 @@ _Instructions for how to setup PiTFT screen can be found [here](https://learn.ad - Reboot your Pi-Hole by running `sudo reboot`. PADD should now run on PiTFT Screen when your Pi-Hole has completed booting. #### (Optional) Put the PiTFT Display to Sleep at Night -_If you don't want your PiTFT on all night when you are asleep, you can put it to sleep! (Note: __these instructions only apply to a PiTFT__.)_ + +_If you don't want your PiTFT on all night when you are asleep, you can put it to sleep! (Note: **these instructions only apply to a PiTFT**.)_ + - To do so, edit cron as root (`sudo crontab -e`) and add the following: + ```bash # PiTFT+ SLEEPY TIME # Turn off the PiTFT+ at midnight @@ -87,31 +116,40 @@ _If you don't want your PiTFT on all night when you are asleep, you can put it t ``` ## Updating PADD + - Simply run + ```bash ./padd.sh -u ``` + - or run the same commands you used to install + ```bash cd ~ wget -O padd.sh https://install.padd.sh ``` + or + ```bash cd ~ curl -sSL https://install.padd.sh -o padd.sh ``` ## Sizes + PADD will display on screens that anywhere from 20x10 characters to over 80x26 characters. As your screen gets smaller, you’ll be presented with less information… however, you’ll always get the most important details: + - The status of your Pi-hole (is it online, in need of an update?), - How many ads have been blocked, - Your hostname and IP, and - Your CPU’s current load. It will also run in the following modes (shown further below): + - Pico: 20x10 characters - Nano: 24x12 characters - Micro: 30x16 characters @@ -122,12 +160,15 @@ It will also run in the following modes (shown further below): - Mega: 80x26 characters ### Sizing Your PADD -How PADD will display on your screen depends on the size of the screen in *characters*, not *pixels*! PADD doesn’t care if it is running on a 5k Retina display on your $5,000 iMac Pro or on a $5 display you bought on eBay. + +How PADD will display on your screen depends on the size of the screen in _characters_, not _pixels_! PADD doesn’t care if it is running on a 5k Retina display on your $5,000 iMac Pro or on a $5 display you bought on eBay. If you want to change how PADD displays on a small display attached to your Raspberry Pi, use + ```bash sudo dpkg-reconfigure console-setup ``` + to configure your font settings to an ideal size for you. If you want to change how PADD displays through a terminal emulator (PuTTY, Terminal.app, iTerm2, etc.), resize your window or play with font sizes in your app of choice. From 3df185411c610920de78de478fc6376a48034371 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Thu, 13 Feb 2025 22:38:44 +0100 Subject: [PATCH 91/96] Add 2FA Signed-off-by: yubiuser --- padd.sh | 71 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/padd.sh b/padd.sh index 8b7e6fd..e24d08b 100755 --- a/padd.sh +++ b/padd.sh @@ -103,7 +103,7 @@ padd_logo_retro_3="${bold_text}${green_text}| ${red_text}/${yellow_text}-${gre TestAPIAvailability() { - local chaos_api_list availabilityResponse cmdResult digReturnCode + local chaos_api_list authResponse cmdResult digReturnCode authStatus authData # Query the API URLs from FTL using CHAOS TXT # The result is a space-separated enumeration of full URLs @@ -138,20 +138,29 @@ TestAPIAvailability() { API_URL="${API_URL#\"}" # Test if the API is available at this URL - availabilityResponse=$(curl --connect-timeout 2 -skS -o /dev/null -w "%{http_code}" "${API_URL}auth") + authResponse=$(curl --connect-timeout 2 -skS -w "%{http_code}" "${API_URL}auth") + + # authStatus are the last 3 characters + # not using ${authResponse#"${authResponse%???}"}" here because it's extremely slow on big responses + authStatus=$(printf "%s" "${authResponse}" | tail -c 3) + # data is everything from response without the last 3 characters + authData=$(printf %s "${authResponse%???}") # Test if http status code was 200 (OK) or 401 (authentication required) - if [ ! "${availabilityResponse}" = 200 ] && [ ! "${availabilityResponse}" = 401 ]; then + if [ ! "${authStatus}" = 200 ] && [ ! "${authStatus}" = 401 ]; then # API is not available at this port/protocol combination API_PORT="" else # API is available at this URL combination - if [ "${availabilityResponse}" = 200 ]; then + if [ "${authStatus}" = 200 ]; then # API is available without authentication needAuth=false fi + # Check if 2FA is required + needTOTP=$(echo "${authData}"| jq --raw-output .session.totp 2>/dev/null) + break fi @@ -178,32 +187,54 @@ TestAPIAvailability() { LoginAPI() { # Exit early if no authentication is required if [ "${needAuth}" = false ]; then - moveXOffset; echo "No password required." + moveXOffset; echo "No authentication required." return fi # Try to read the CLI password (if enabled and readable by the current user) if [ -r /etc/pihole/cli_pw ]; then password=$(cat /etc/pihole/cli_pw) - - # Try to authenticate using the CLI password - Authenticate fi - # If this did not work, ask the user for the password - while [ "${validSession}" = false ] || [ -z "${validSession}" ] ; do + if [ -z "${password}" ]; then + # no password was supplied as argument or read from CLI file + moveXOffset; echo "No password supplied. Please enter your password:" + # secretly read the password + moveXOffset; secretRead; printf '\n' + fi + + if [ "${needTOTP}" = true ] && [ -z "${totp}" ]; then + # 2FA required, but no TOTP was supplied as argument + moveXOffset; echo "Please enter the correct second factor:" + moveXOffset; read -r totp + fi + + # Try to authenticate using the supplied password (CLI file, argument or user input) and TOTP + Authenticate + + # Try to login again until the session is valid + while [ ! "${validSession}" = true ] ; do moveXOffset; echo "Authentication failed." - # no password was supplied as argument - if [ -z "${password}" ]; then - moveXOffset; echo "No password supplied. Please enter your password:" - else - moveXOffset; echo "Wrong password supplied, please enter the correct password:" + # Print the error message if there is one + if [ ! "${sessionError}" = "null" ]; then + moveXOffset; echo "Error: ${sessionError}" fi + # Print the session message if there is one + if [ ! "${sessionMessage}" = "null" ]; then + moveXOffset; echo "Error: ${sessionMessage}" + fi + + moveXOffset; echo "Please enter the correct password:" # secretly read the password moveXOffset; secretRead; printf '\n' + if [ "${needTOTP}" = true ]; then + moveXOffset; echo "Please enter the correct second factor:" + moveXOffset; read -r totp + fi + # Try to authenticate again Authenticate done @@ -233,16 +264,20 @@ DeleteSession() { } Authenticate() { - sessionResponse="$(curl --connect-timeout 2 -skS -X POST "${API_URL}auth" --user-agent "PADD ${padd_version}" --data "{\"password\":\"${password}\"}" )" + sessionResponse="$(curl --connect-timeout 2 -skS -X POST "${API_URL}auth" --user-agent "PADD ${padd_version}" --data "{\"password\":\"${password}\", \"totp\":${totp:-null}}" )" if [ -z "${sessionResponse}" ]; then moveXOffset; echo "No response from FTL server. Please check connectivity and use the options to set the API URL" moveXOffset; echo "Usage: $0 [--server ]" exit 1 fi - # obtain validity and session ID from session response + # obtain validity, session ID and sessionMessage from session response validSession=$(echo "${sessionResponse}"| jq .session.valid 2>/dev/null) SID=$(echo "${sessionResponse}"| jq --raw-output .session.sid 2>/dev/null) + sessionMessage=$(echo "${sessionResponse}"| jq --raw-output .session.message 2>/dev/null) + + # obtain the error message from the session response + sessionError=$(echo "${sessionResponse}"| jq --raw-output .error.message 2>/dev/null) } GetFTLData() { @@ -1757,6 +1792,7 @@ DisplayHelp() { ::: ::: --server domain or IP of your Pi-hole (default: localhost) ::: --secret your Pi-hole's password, required to access the API +::: --2fa <2fa> your Pi-hole's 2FA code, if 2FA is enabled ::: -j, --json output stats as JSON formatted string and exit ::: -u, --update update to the latest version ::: -v, --version show PADD version info @@ -1857,6 +1893,7 @@ while [ "$#" -gt 0 ]; do "--yoff" ) yOffset="$2"; yOffOrig="$2"; shift;; "--server" ) SERVER="$2"; shift;; "--secret" ) password="$2"; shift;; + "--2fa" ) totp="$2"; shift;; * ) DisplayHelp; exit 1;; esac shift From f697f997e3b8b5b4a81df92019916281b441e2f2 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Sat, 15 Feb 2025 23:05:11 +0100 Subject: [PATCH 92/96] If a CLI password is found, 2FA can be skipped Signed-off-by: yubiuser --- padd.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/padd.sh b/padd.sh index e24d08b..18f5f1b 100755 --- a/padd.sh +++ b/padd.sh @@ -194,6 +194,8 @@ LoginAPI() { # Try to read the CLI password (if enabled and readable by the current user) if [ -r /etc/pihole/cli_pw ]; then password=$(cat /etc/pihole/cli_pw) + # If we can read the CLI password, we can skip 2FA even when it's required + needTOTP=false fi if [ -z "${password}" ]; then From a0833eefab87f0110490765ca9a6502215523b9c Mon Sep 17 00:00:00 2001 From: yubiuser Date: Sun, 16 Feb 2025 08:58:38 +0100 Subject: [PATCH 93/96] Add hint to skip 2FA in case the app password was used Signed-off-by: yubiuser --- padd.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/padd.sh b/padd.sh index 18f5f1b..329e597 100755 --- a/padd.sh +++ b/padd.sh @@ -194,7 +194,7 @@ LoginAPI() { # Try to read the CLI password (if enabled and readable by the current user) if [ -r /etc/pihole/cli_pw ]; then password=$(cat /etc/pihole/cli_pw) - # If we can read the CLI password, we can skip 2FA even when it's required + # If we can read the CLI password, we can skip 2FA even when it's required otherwise needTOTP=false fi @@ -207,7 +207,8 @@ LoginAPI() { if [ "${needTOTP}" = true ] && [ -z "${totp}" ]; then # 2FA required, but no TOTP was supplied as argument - moveXOffset; echo "Please enter the correct second factor:" + moveXOffset; echo "Please enter the correct second factor." + moveXOffset; echo "(Can be any number if you used the app password)" moveXOffset; read -r totp fi @@ -234,6 +235,7 @@ LoginAPI() { if [ "${needTOTP}" = true ]; then moveXOffset; echo "Please enter the correct second factor:" + moveXOffset; echo "(Can be any number if you used the app password)" moveXOffset; read -r totp fi From a35806ca42e7e71a7f8785f6546e6456d7f8ded5 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Tue, 18 Feb 2025 21:38:19 +0100 Subject: [PATCH 94/96] Correct location of the cli password file Signed-off-by: yubiuser --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3dad3b6..1165c55 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ With PADD v4.0.0 and Pi-hole v6 it is also possible to run PADD from a machine t Pi-hole v6 uses a completely new API with a new authentication mechanism -If you run PADD on the same machine as Pi-hole, it's possible to bypass authentication when your local user is member of the `pihole` group (specifically, if you can access `/etc/pihole/cli_password). +If you run PADD on the same machine as Pi-hole, it's possible to bypass authentication when your local user is member of the `pihole` group (specifically, if you can access `/etc/pihole/cli_pw). For details see [https://github.com/pi-hole/FTL/pull/1999](https://github.com/pi-hole/FTL/pull/1999) If this is not the case, PADD will ask you for your password and (if configured) your two factor authentication token. You can also pass those as arguments From a0df3ff6c54586bc272c8be4ca617c05dbc7245f Mon Sep 17 00:00:00 2001 From: yubiuser Date: Sun, 23 Feb 2025 21:40:27 +0100 Subject: [PATCH 95/96] Fix IPv4 address indicator Signed-off-by: yubiuser --- padd.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/padd.sh b/padd.sh index 329e597..8e3f582 100755 --- a/padd.sh +++ b/padd.sh @@ -527,8 +527,9 @@ GetNetworkInformation() { if [ "${pi_ip4_addrs}" -eq 0 ]; then # No IPv4 address available pi_ip4_addr="N/A" - #elif [ "${pi_ip4_addrs}" -eq 1 ]; then - # # One IPv4 address available + elif [ "${pi_ip4_addrs}" -eq 1 ]; then + # One IPv4 address available + : # Do nothing as the address is already set else # More than one IPv4 address available pi_ip4_addr="${pi_ip4_addr}+" From 57b3ff8d9874486c04ec92a774a6c451af7f4146 Mon Sep 17 00:00:00 2001 From: yubiuser Date: Sun, 23 Feb 2025 22:16:55 +0100 Subject: [PATCH 96/96] Only exit for small screen sizes during startup Signed-off-by: yubiuser --- padd.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/padd.sh b/padd.sh index 329e597..2034f28 100755 --- a/padd.sh +++ b/padd.sh @@ -1323,9 +1323,7 @@ SizeChecker(){ height=10 # Below Pico. Gives you nothing... else - # Nothing is this small, sorry - printf "%b" "${check_box_bad} Error!\n PADD isn't\n for ants!\n" - exit 1 + padd_size="ants" fi # Center the output (default position) @@ -1537,6 +1535,12 @@ ShowVersion() { StartupRoutine(){ + if [ "$1" = "ants" ]; then + # If the screen is too small from the beginning, exit + printf "%b" "${check_box_bad} Error!\n PADD isn't\n for ants!\n" + exit 1 + fi + # Clear the screen and move cursor to (0,0). # This mimics the 'clear' command. # https://vt100.net/docs/vt510-rm/ED.html