From e23249c733bbe3aa9e5f2cd352f664e270e964cb Mon Sep 17 00:00:00 2001 From: Bruno21 Date: Fri, 1 Nov 2024 12:15:47 +0100 Subject: [PATCH] 1st commit -urls_check.sh check status code and certificate validity for a list of domains (urls_list.txt) -validity.sh only check certificate validity for an array of domains -both send notification if certificate is outdated. --- status.txt | 67 ++++++++++++ urls_check.sh | 290 ++++++++++++++++++++++++++++++++++++++++++++++++++ validity.sh | 163 ++++++++++++++++++++++++++++ 3 files changed, 520 insertions(+) create mode 100644 status.txt create mode 100755 urls_check.sh create mode 100755 validity.sh diff --git a/status.txt b/status.txt new file mode 100644 index 0000000..18c8899 --- /dev/null +++ b/status.txt @@ -0,0 +1,67 @@ +100;Continue;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/100 +101;Switching Protocol;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/101 +102;Processing;https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/102 +103;Early Hints;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/103 + +200;OK;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/200 +201;Created;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/201 +202;Accepted;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/202 +203;Non-authoritative Information;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/203 +204;Np content;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/204 +205;Reset Content;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/205 +206;Partial Content;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/206 +207;Multi-Status;https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/207 +208;Already Reported;https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/208 +226;IM Used;https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/226 + +300;Multiple Choices;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/300 +301;Moved Permanently;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/301 +302;Found;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/302 +303;See Other;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/303 +304;Not Modified;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/304 +307;Temporary Redirect;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/307 +308;Permanent Redirect;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/308 + +400;Bad Request;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/400 +401;Unauthorized;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/401 +402;Payment Required;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/402 +403;Forbidden;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/403 +404;Not Found;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/404 +405;Method Not Allowed;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/405 +406;Not Acceptable;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/406 +407;Proxy Authentication Required;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/407 +408;Request Timeout;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/408 +409;Conflict;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/409 + +410;Gone;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/410 +411;Length Required;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/411 +412;Precondition Failed;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/412 +413;Payload Too Large;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/413 +414;URI Too Long;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/414 +415;Unsupported Media Type;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/415 +416;Range Not Satisfiable;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/416 +417;Expectation Failed;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/417 +418;I'm a teapot (je suis une théière);https://developer.mozilla.org/fr/docs/Web/HTTP/Status/418 + +421;Misdirected Request;https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/421 +422;Unprocessable Entity;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/422 +423;Locked;https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/423 +424;Failed Dependency;https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/424 +425;Too Early;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/425 +426;Upgrade Required;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/426 +428;Precondition Required;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/428 +429;Too Many Requests;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/429 +431;Request Header Fields Too Large;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/431 +451;Unavailable For Legal Reasons;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/451 + +500;Internal Server Error;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/500 +501;Not Implemented;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/501 +502;Bad Gateway;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/502 +503;Service Unavailable;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/503 +504;Gateway Timeout;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/504 +505;HTTP Version Not Supported;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/505 +506;Variant Also Negotiates;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/506 +507;Insufficient Storage;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/507 +508;Loop Detected;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/508 +510;Not Extended;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/510 +511;Network Authentication Required;https://developer.mozilla.org/fr/docs/Web/HTTP/Status/511 diff --git a/urls_check.sh b/urls_check.sh new file mode 100755 index 0000000..512f08c --- /dev/null +++ b/urls_check.sh @@ -0,0 +1,290 @@ +#!/usr/bin/env bash + +italic="\033[3m" +underline="\033[4m" +ita_under="\033[3;4m" +bgd="\033[1;4;31m" +red="\033[0;31m" +bold="\033[1m" +bold_ita="\033[1;3m" +box="\033[1;41m" +redbold="\033[1;31m" +redbox="\033[1;41m" +green="\033[0;32m" +greenbold="\033[1;32m" +reset="\033[0m" + +command -v showcert >/dev/null 2>&1 || { echo -e "${bold}showcert${reset} is not installed ${italic}(pip install showcert)${reset}. Aborting..." >&2; exit 1; } + +cat < /dev/null > /dev/tcp/1.1.1.1/53 +if [[ $? -ne 0 ]]; then + echo -e "\n${red}No Internet connection !${reset}" + echo -e "Exit !" + exit 1 +fi + +#urls=("https://clicclac.info" "https://clicclac.info/wordpress" "https://sur-le-sentier.fr" "https://maboiteverte.fr") +urls=() +port=443 +# Days left before notification +nday=15 +# Choose the notification +notif="pushover" + +not_required_domains="$HOME/Documents/Scripts/pihole/sync_pihole_lan.sh" + + +dotenv () { + set -a + # shellcheck disable=SC1091 + [ -f "$HOME/.env" ] && . "$HOME/.env" || echo -e "${red}\nNo .env file found ! Could'nt get update from Github or send notification.'.${reset}" + set +a +} + +dotenv + +send_gotify_notification() { + # Enabled HSTS & created default WebSocket records in the DSM 7.2 reverse proxy window and it solved itself. + + now=$(date +"%d-%m-%Y %T") + gotify_server="https://gotify.maboiteverte.fr" + gotify_token="$GOTIFY_BASH" + TITLE="$1" + MESSAGE="$2" + PRIORITY=8 + URL="$gotify_server/message?token=$gotify_token&?format=markdown" + + echo -e "Sending notification to $gotify_server ..." + # -S, --show-error Show error even when -s is used + # -s, --silent Silent mode + # -v Verbose + + curl -s -S --output /dev/null --data '{"message": "'"${MESSAGE}"'", "title": "'"${TITLE}"'", "priority":'"${PRIORITY}"', "extras": {"client::display": {"contentType": "text/markdown"}}}' -H 'Content-Type: application/json' "$URL" + + [ $? -eq 0 ] && echo -e "${greenbold}Gotify notification sent successfully !${reset}" || echo -e "${redbold}error sending Gotify notification !${reset}" +} + +send_pushover_notification() { + echo -e "Sending Pushover notification ..." + curl -S -s -o /dev/null -F "token=$BASH_APP" \ + -F "user=$USER_KEY" \ + -F "title=$1" \ + -F priority=2 \ + -F html=1 \ + -F retry=60 \ + -F expire=86400 \ + -F "message=$2" https://api.pushover.net/1/messages.json + + [ $? -eq 0 ] && echo -e "${greenbold}Pushover notification sent successfully !${reset}" || echo -e "${redbold}error sending Pushover notification !${reset}" +} + +status_error() { + info_code=$(grep "$1" ./status.txt) + status_code=$(echo "$info_code" | awk -F";" '{print $1}') + status_title=$(echo "$info_code" | awk -F";" '{print $2}') + status_url=$(echo "$info_code" | awk -F";" '{print $3}') + printf " %-3s %-25s %-95s \n" $status_code "$status_title" "$status_url" +} + +display_help() { + # taken from https://stackoverflow.com/users/4307337/vincent-stans + echo "Usage: $0 " >&2 + echo + echo "urls_check.sh will read a list of urls in urls_list.txt file, then return the status code for each url." + echo "If the site is up (status code: 200, 301, 302, 303, 307), then certificate information will be displayed." + echo "If the site is down or the certificate is outdated, a Pushover (or Gotify) notification will be sent." + echo "status.txt give description and a link to Mozilla for each status code." + echo + # echo some stuff here for the -a or --add-options + exit 1 +} + +while [[ "$#" -gt 0 ]]; do + case $1 in + -h|--help) display_help; shift ;; + *) echo "Unknown parameter passed: $1" ;; + esac + shift +done + + +# Chargement de la liste des urls depuis urls_list.txt + +while read -r line +do + [ ${line:0:1} != "#" ] && urls+=("$line") +done < urls_list.txt + +# Ajout des domaines non-requis + +if [ -f "$not_required_domains" ]; then + #a=$(grep 'not_required=' sync_pihole_lan.sh) + a=$(grep 'not_required=' $not_required_domains) + + b=$(echo "$a" | awk -F"=" '{split($2, arr, "[()]"); print arr[2]}' | sed 's/\"//g') + not_required=(${b}) + + for val in "${!not_required[@]}" + do + z="https://${not_required[$val]}.photos-nas.ovh" + urls+=("${z}") + done + +else + echo "file $not_required_domains not find !" + echo "Domain like drive.photos-nas.ovh won't be checked.'" +fi + +# Tri du tableau d'urls + +IFS=$'\n' urls_sorted=($(sort <<<"${urls[*]}")) +unset IFS + +urls=() +newArr=() +while IFS= read -r -d '' x +do + urls+=("$x") +done < <(printf "%s\0" "${urls_sorted[@]}" | sort -uz) + +# On efface la liste des urls down + +[ -f "./urls_down_list_curl.txt" ] && rm "./urls_down_list_curl.txt" +[ -f "./certificats_outdated.txt" ] && rm "./certificats_outdated.txt" + + +check_url() { + website=$(echo "$1" | awk -F "\/\/" '{print $2}') + response=$(curl --connect-timeout 10 --max-time 10 --retry 3 --retry-delay 0 --retry-max-time 30 --write-out '%{http_code}' --silent --output /dev/null "$1") + + if [ $(grep -w "200\|301\|302\|303\|307" <<< "$response") ];then + echo -e "${greenbold}$2. $website is up${reset} ($response)" + + # Si le serveur répond correctement, on affiche la validité du certificat + info_certif "$1" + + else + echo -e "${redbold}$2. $1 is down${reset} ($response)" + echo "$1 is down ($response)" >> urls_down_list_curl.txt + + # Affichage et description de l'erreur + status_error "$response" + echo -e "\n" + + # Tableau des non-réponses uniques + if [[ " ${array_responses[*]} " != *"$response"* ]]; then + array_responses+=("$response") + fi + + fi +} + +info_certif() { + # cn=$(echo | openssl s_client -connect $1 2>/dev/null | openssl x509 -noout -subject -dates -issuer) + + domain=$(echo "$1" | grep -Eo '^http[s]?://[^/]+' | cut -c 9- ) + cert=$(showcert "$domain") + + ip=$(echo "$cert" | grep IP | awk -F": " '{print $2}') + names=$(echo "$cert" | grep Names | awk -F": " '{print $2}') + issuer=$(echo "$cert" | grep Issuer | awk -F": " '{print $2}') + start=$(echo "$cert" | grep Before | awk -F": " '{print $2}') + end=$(echo "$cert" | grep notAfter | awk -F": " '{print $2}') + left=$(echo "$end" | awk -F" " '{split($3, arr, "[()]"); print arr[2]}') + + [ $left -lt $nday ] && echo -e "${red}" + echo -e "Names: $names" + echo -e "Issuer: $issuer" + echo -e "Date début: $start" + echo -e "Date fin: $end\n" + [ $left -lt $nday ] && echo -e "${reset}" + + if [ $left -lt $nday ]; then + echo "certif outdated..." + if [[ " ${array_names[*]} " != *"$names"* ]]; then + array_names+=("$names") + + #echo "Domain: $domain" >> certificats_outdated.txt + echo "Names: $names" >> certificats_outdated.txt + echo "Issuer: $issuer" >> certificats_outdated.txt + echo "Date début: $start" >> certificats_outdated.txt + echo "Date fin: $end" >> certificats_outdated.txt + echo "" >> certificats_outdated.txt + fi + + fi + +} + +: << 'COMMENTS2' +COMMENTS2 + + +i=1 +array_names=() +array_responses=() + +for url in "${!urls[@]}" +do + check_url "${urls[$url]}" "$i" + ((i=i+1)) + + if [ "$i" -gt 13 ]; then + break + fi + +done + + +# Affichage des serveurs qui ne répondent pas + +echo -e "\n${redbold}Url down: ${reset}" +if [ -f "./urls_down_list_curl.txt" ]; then + cp "./urls_down_list_curl.txt" urls_down_list_curl.bak + url_down=$(cat "./urls_down_list_curl.txt") + echo -e "$url_down\n" + + # On affiche uniquement les erreurs rencontrées + for val in ${!array_responses[@]} + do + a="${array_responses[$val]}" + status_error "$a" + done + echo "" + + if [ "$notif" == "gotify" ];then + msg_md="$url_down" + # MESSAGE="**A new version of Pi-hole is available:**\n\n $msg_md\n\n $infos\n\n Please run *pihole -up* on $host to update !" + send_gotify_notification "Several url are down !" "$msg_md" + elif [ "$notif" == "pushover" ];then + msg_html="$url_down" + send_pushover_notification "Several url are down !" "$msg_html" + #pushover -a "bash" -m "A new version of Pi-hole is available:
$msg_html
$infos_html
Please run pihole -up on $host to update" -p 2 -f 1 + fi + +fi + + +# Liste des certificat pas à jour + +if [ -f "./certificats_outdated.txt" ]; then + echo -e "\n${redbold}Certificat outdated: ${reset}" + + certif_outdated=$(cat "./certificats_outdated.txt") + echo -e "$certif_outdated\n" + + if [ "$notif" == "gotify" ];then + msg_md="$certif_outdated" + # MESSAGE="**A new version of Pi-hole is available:**\n\n $msg_md\n\n $infos\n\n Please run *pihole -up* on $host to update !" + send_gotify_notification "Several certificats are outdated !" "$msg_md" + elif [ "$notif" == "pushover" ];then + msg_html="$certif_outdated" + send_pushover_notification "Several certificats are outdated !" "$msg_html" + #pushover -a "bash" -m "A new version of Pi-hole is available:
$msg_html
$infos_html
Please run pihole -up on $host to update" -p 2 -f 1 + fi + +else + echo -e "${green}\nNo certificat outdated !${reset}" +fi + +# curl --write-out "%{json}" https://nextcloud.photos-nas.ovh | jq diff --git a/validity.sh b/validity.sh new file mode 100755 index 0000000..7483689 --- /dev/null +++ b/validity.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env bash +# Check SSL certificates for key domains +# +# Run: ./validity.sh + +VERSION="v0.9" + +red="\033[1;31m" +greenbold="\033[1;32m" +green="\033[0;32m" +yellow="\033[0;33m" +yellowbold="\033[1;33m" +bold="\033[1m" +italic="\033[3m" +#bold_under="\033[1;4m" +underline="\033[4m" +reset="\033[0m" + +#echo | openssl s_client -servername maboiteverte.fr -connect maboiteverte.fr:443 2>/dev/null | openssl x509 -noout -issuer -subject -dates + +#export PATH="/usr/local/bin:$PATH" +# run by cron $PATH=/usr/bin:/bin + +#command -v showcert >/dev/null 2>&1 || { echo -e "${bold}showcert${reset} is not installed ${italic}(pip install showcert)${reset}. Aborting..." >&2; exit 1; } + +curl -Is https://www.apple.com | head -1 | grep 200 1>/dev/null +if [ $? -eq 1 ]; then + echo -e "\n${red}No Internet connection !${reset}" + echo -e "Exit !" + exit 1 +fi + +hosts=("maboiteverte.fr" "sur-le-sentier.fr" "photos-nas.ovh" "clicclac.info") +#hosts=("maboiteverte.fr") +port=443 +# Days left before notification +nday=15 +# Choose the notification +notif="pushover" + +dotenv () { + set -a + # shellcheck disable=SC1091 + [ -f "$HOME/.env" ] && . "$HOME/.env" || echo -e "${red}\nNo .env file found ! No token for gotify.${reset}" + set +a +} + +dotenv + +send_gotify_notification() { + # Enabled HSTS & created default WebSocket records in the DSM 7.2 reverse proxy window and it solved itself. + + now=$(date +"%d-%m-%Y %T") + gotify_server="https://gotify.maboiteverte.fr" + gotify_token="$GOTIFY_BASH" + TITLE="$1" + MESSAGE="**A new version of Pi-hole is available:**\n\n $msg_md\n\n $infos\n\n Please run *pihole -up* on $host to update !" + PRIORITY=8 + URL="$gotify_server/message?token=$gotify_token&?format=markdown" + + echo -e "Sending notification to $gotify_server ..." + # -S, --show-error Show error even when -s is used + # -s, --silent Silent mode + # -v Verbose + + curl -s -S --output /dev/null --data '{"message": "'"${MESSAGE}"'", "title": "'"${TITLE}"'", "priority":'"${PRIORITY}"', "extras": {"client::display": {"contentType": "text/markdown"}}}' -H 'Content-Type: application/json' "$URL" + + [ $? -eq 0 ] && echo -e "${greenbold}Gotify notification sent successfully !${reset}" || echo -e "${redbold}error sending Gotify notification !${reset}" +} + +send_pushover_notification() { + echo -e "Sending Pushover notification ..." + curl -S -s -o /dev/null -F "token=$BASH_APP" \ + -F "user=$USER_KEY" \ + -F "title=$1" \ + -F priority=2 \ + -F html=1 \ + -F retry=60 \ + -F expire=86400 \ + -F "message=$2" https://api.pushover.net/1/messages.json + + [ $? -eq 0 ] && echo -e "${greenbold}Pushover notification sent successfully !${reset}" || echo -e "${redbold}error sending Pushover notification !${reset}" +} + + +for host in "${hosts[@]}"; do + if command -v showcertif >/dev/null 2>&1; then + cert=$(showcert $host) + + ip=$(echo "$cert" | grep IP | awk -F": " '{print $2}') + names=$(echo "$cert" | grep Names | awk -F": " '{print $2}') + issuer=$(echo "$cert" | grep Issuer | awk -F": " '{print $2}') + start=$(echo "$cert" | grep Before | awk -F": " '{print $2}') + end=$(echo "$cert" | grep notAfter | awk -F": " '{print $2}') + left=$(echo "$end" | awk -F" " '{split($3, arr, "[()]"); print arr[2]}') + + # maboiteverte.fr + # IP: 212.227.191.167 + # Names: *.maboiteverte.fr maboiteverte.fr + # notBefore: 2024-01-08 00:00:00 (298 days old) + # notAfter: 2025-01-27 23:59:59 (87 days left) + # Issuer: C=US O=DigiCert Inc OU=www.digicert.com CN=Encryption Everywhere DV TLS CA - G2 + # Tags: [CHAIN-VERIFIED] + + h="$host ($ip)" + n="Names: $names" + i="Issuer: $issuer" + s="Date début: $start" + e="Date fin: $end" + + else + cert=`echo | + openssl s_client -connect $host:$port 2>/dev/null | + openssl x509 -issuer -subject -dates -noout` + + issuer=$(echo "$cert" | grep issuer | awk -F"issuer=" '{print $2}') + subject=$(echo "$cert" | grep subject | awk -F"subject=" '{print $2}') + start=$(echo "$cert" | grep Before | awk -F"=" '{print $2}') + end=$(echo "$cert" | grep notAfter | awk -F"=" '{print $2}') + timestamp_current=$(date +"%s") + timestamp_end=$(date --date="$end" +"%s") + left=$(($((timestamp_end - timestamp_current))/(60*60*24))) + end="$end ($left days left)" + + ip=$(dig +short $host) + # issuer=C=US, O=DigiCert Inc, OU=www.digicert.com, CN=Encryption Everywhere DV TLS CA - G2 + # subject=CN=*.maboiteverte.fr + # notBefore=Jan 8 00:00:00 2024 GMT + # notAfter=Jan 27 23:59:59 2025 GMT + + h="$host ($ip)" + n="Subject: $subject" + i="Issuer: $issuer" + s="Date début: $start" + e="Date fin: $end" + + fi + + echo -e "${bold}$h${reset}" + echo -e "$n" + echo -e "$i" + echo -e "$s" + + if [ $left -lt $nday ]; then + echo -e "${red}$e${reset}" + + # Run by cron + if [ "$notif" == "gotify" ];then + msg_md="**$h**\n\n $n\n\n $i\n\n $s\n\n $e" + send_gotify_notification "$host certificat will expire in $left day !" "$msg_md" + elif [ "$notif" == "pushover" ];then + msg_html="$h
$n
$i
$s
$e" + send_pushover_notification "$host certificat will expire in $left day !" "$msg_html" + #pushover -a "bash" -m "A new version of Pi-hole is available:
$msg_html
$infos_html
Please run pihole -up on $host to update" -p 2 -f 1 + fi + + else + echo -e "${green}$e${reset}" + fi + + echo -e "\n" + sleep 1 +done