From db955263edc53c025a738afde3433a9d6592bf10 Mon Sep 17 00:00:00 2001 From: scriptos Date: Fri, 6 Mar 2026 13:04:19 +0100 Subject: [PATCH 1/3] Email-Reports werden jetzt sauber erzeugt. --- report-generator.sh | 62 ++++++++++++++++++++++++++++++------------- templates/report.html | 2 +- templates/report.txt | 2 +- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/report-generator.sh b/report-generator.sh index e3a8801..5574ee1 100644 --- a/report-generator.sh +++ b/report-generator.sh @@ -62,35 +62,43 @@ log() { local message="$*" local timestamp timestamp="$(date '+%Y-%m-%d %H:%M:%S')" - echo "[$timestamp] [$level] [REPORT] $message" | tee -a "$LOG_FILE" + echo "[$timestamp] [$level] [REPORT] $message" | tee -a "$LOG_FILE" >&2 } # ─── Berichtszeitraum berechnen ─────────────────────────────────────────────── + +# Gibt Epoch-Wert für heute 00:00:00 (Mitternacht) zurück +get_today_midnight() { + date -d "today 00:00:00" '+%s' 2>/dev/null || date -v0H -v0M -v0S '+%s' +} + get_report_period() { - local now_epoch - now_epoch=$(date '+%s') + local today_midnight + today_midnight=$(get_today_midnight) + # Ende des Berichtszeitraums ist immer das Ende von gestern (23:59:59) + local end_epoch=$((today_midnight - 1)) local start_epoch local period_label case "$REPORT_INTERVAL" in daily) - start_epoch=$((now_epoch - 86400)) + start_epoch=$((today_midnight - 86400)) period_label="Tagesbericht" ;; weekly) - start_epoch=$((now_epoch - 604800)) + start_epoch=$((today_midnight - 7 * 86400)) period_label="Wochenbericht" ;; biweekly) - start_epoch=$((now_epoch - 1209600)) + start_epoch=$((today_midnight - 14 * 86400)) period_label="Zweiwochenbericht" ;; monthly) - start_epoch=$((now_epoch - 2592000)) + start_epoch=$((today_midnight - 30 * 86400)) period_label="Monatsbericht" ;; *) - start_epoch=$((now_epoch - 604800)) + start_epoch=$((today_midnight - 7 * 86400)) period_label="Bericht" ;; esac @@ -98,28 +106,40 @@ get_report_period() { local start_date start_date=$(date -d "@$start_epoch" '+%d.%m.%Y' 2>/dev/null || date -r "$start_epoch" '+%d.%m.%Y') local end_date - end_date=$(date '+%d.%m.%Y') + end_date=$(date -d "@$end_epoch" '+%d.%m.%Y' 2>/dev/null || date -r "$end_epoch" '+%d.%m.%Y') - echo "${period_label}: ${start_date} – ${end_date}" + if [[ "$REPORT_INTERVAL" == "daily" ]]; then + echo "${period_label}: ${start_date}" + else + echo "${period_label}: ${start_date} – ${end_date}" + fi } get_period_start_epoch() { - local now_epoch - now_epoch=$(date '+%s') + local today_midnight + today_midnight=$(get_today_midnight) case "$REPORT_INTERVAL" in - daily) echo $((now_epoch - 86400)) ;; - weekly) echo $((now_epoch - 604800)) ;; - biweekly) echo $((now_epoch - 1209600)) ;; - monthly) echo $((now_epoch - 2592000)) ;; - *) echo $((now_epoch - 604800)) ;; + daily) echo $((today_midnight - 86400)) ;; + weekly) echo $((today_midnight - 7 * 86400)) ;; + biweekly) echo $((today_midnight - 14 * 86400)) ;; + monthly) echo $((today_midnight - 30 * 86400)) ;; + *) echo $((today_midnight - 7 * 86400)) ;; esac } +get_period_end_epoch() { + # Ende des Berichtszeitraums = Ende von gestern (heute 00:00:00 minus 1 Sekunde) + local today_midnight + today_midnight=$(get_today_midnight) + echo $((today_midnight - 1)) +} + # ─── Ban-History filtern nach Zeitraum ──────────────────────────────────────── # Gibt nur Zeilen zurück, deren Zeitstempel im Berichtszeitraum liegen filter_history_by_period() { local start_epoch="$1" + local end_epoch="$2" if [[ ! -f "$BAN_HISTORY_FILE" ]]; then return @@ -141,7 +161,7 @@ filter_history_by_period() { local line_epoch line_epoch=$(date -d "$timestamp" '+%s' 2>/dev/null || date -j -f '%Y-%m-%d %H:%M:%S' "$timestamp" '+%s' 2>/dev/null || echo "0") - if [[ "$line_epoch" -ge "$start_epoch" ]]; then + if [[ "$line_epoch" -ge "$start_epoch" && "$line_epoch" -le "$end_epoch" ]]; then echo "$line" fi done < "$BAN_HISTORY_FILE" @@ -194,9 +214,11 @@ calculate_stats() { local start_epoch start_epoch=$(get_period_start_epoch) + local end_epoch + end_epoch=$(get_period_end_epoch) local filtered_data - filtered_data=$(filter_history_by_period "$start_epoch") + filtered_data=$(filter_history_by_period "$start_epoch" "$end_epoch") # Wenn keine Daten vorhanden, Standardwerte if [[ -z "$filtered_data" ]]; then @@ -373,6 +395,7 @@ generate_recent_bans_html() { while IFS='|' read -r timestamp action ip domain count duration protocol reason; do timestamp=$(echo "$timestamp" | xargs) ip=$(echo "$ip" | xargs) + [[ -z "$timestamp" && -z "$ip" ]] && continue domain=$(echo "$domain" | xargs) reason=$(echo "$reason" | xargs) [[ "$domain" == "-" ]] && domain="–" @@ -459,6 +482,7 @@ generate_recent_bans_txt() { while IFS='|' read -r timestamp action ip domain count duration protocol reason; do timestamp=$(echo "$timestamp" | xargs) ip=$(echo "$ip" | xargs) + [[ -z "$timestamp" && -z "$ip" ]] && continue domain=$(echo "$domain" | xargs) reason=$(echo "$reason" | xargs) [[ "$domain" == "-" ]] && domain="–" diff --git a/templates/report.html b/templates/report.html index 869e725..735db8c 100644 --- a/templates/report.html +++ b/templates/report.html @@ -311,7 +311,7 @@ | AdGuard Shield auf Gitea -
AdGuard Shield v{{VERSION}} · {{HOSTNAME}}
+
AdGuard Shield {{VERSION}} · {{HOSTNAME}}
diff --git a/templates/report.txt b/templates/report.txt index aeb55d8..b582243 100644 --- a/templates/report.txt +++ b/templates/report.txt @@ -52,7 +52,7 @@ ═══════════════════════════════════════════════════════════════ Dieser Report wurde automatisch von AdGuard Shield generiert. - AdGuard Shield v{{VERSION}} + AdGuard Shield {{VERSION}} Web: https://www.patrick-asmus.de Blog: https://www.cleveradmin.de From fd8388df0ba000d2a2b21e4e18c033952fd83c52 Mon Sep 17 00:00:00 2001 From: scriptos Date: Fri, 6 Mar 2026 13:12:36 +0100 Subject: [PATCH 2/3] Uninstaller ausgelagert. --- README.md | 6 +- doc/befehle.md | 13 +++- doc/tipps-und-troubleshooting.md | 9 ++- install.sh | 24 ++++-- uninstall.sh | 129 +++++++++++++++++++++++++++++++ 5 files changed, 172 insertions(+), 9 deletions(-) create mode 100644 uninstall.sh diff --git a/README.md b/README.md index 450ebac..f1cd6d7 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,9 @@ sudo bash install.sh --help # Hilfe anzeigen sudo bash install.sh update # Update mit automatischer Konfigurations-Migration sudo bash install.sh status # Installationsstatus prüfen +# Deinstallation (kein install.sh benötigt) +sudo bash /opt/adguard-shield/uninstall.sh # Direkt aus dem Installationsverzeichnis + # Monitor sudo /opt/adguard-shield/adguard-shield.sh status # Aktive Sperren anzeigen sudo /opt/adguard-shield/adguard-shield.sh history # Ban-History anzeigen @@ -103,7 +106,8 @@ sudo journalctl -u adguard-shield -f # Logs live ver ├── iptables-helper.sh # Manuelle iptables-Verwaltung ├── unban-expired.sh # Cron-basiertes Entsperren ├── report-generator.sh # E-Mail Report Generator -├── install.sh # Installer / Updater / Uninstaller +├── install.sh # Installer / Updater +├── uninstall.sh # Uninstaller (wird ins Installationsverzeichnis kopiert) ├── templates/ │ ├── report.html # HTML-Report-Template │ └── report.txt # TXT-Report-Template diff --git a/doc/befehle.md b/doc/befehle.md index 0d85fe3..4915e3c 100644 --- a/doc/befehle.md +++ b/doc/befehle.md @@ -14,7 +14,7 @@ sudo bash install.sh install # Update (mit automatischer Konfigurations-Migration) sudo bash install.sh update -# Deinstallation +# Deinstallation (delegiert automatisch an den installierten Uninstaller) sudo bash install.sh uninstall # Installationsstatus anzeigen @@ -24,6 +24,17 @@ sudo bash install.sh status sudo bash install.sh --help ``` +## Uninstaller (eigenständig) + +Ab Version 0.6 wird bei der Installation ein eigenständiger Uninstaller nach `/opt/adguard-shield/uninstall.sh` kopiert. Die Deinstallation kann damit **ohne die originalen Installationsdateien** durchgeführt werden: + +```bash +# Direkt aus dem Installationsverzeichnis — kein install.sh benötigt +sudo bash /opt/adguard-shield/uninstall.sh +``` + +Der Uninstaller kennt seinen Speicherort und leitet daraus automatisch das Installationsverzeichnis ab. `install.sh uninstall` delegiert intern ebenfalls dorthin — beide Wege führen zum selben Ergebnis. + ### Update-Verhalten Beim Update passiert automatisch: diff --git a/doc/tipps-und-troubleshooting.md b/doc/tipps-und-troubleshooting.md index 204dc3b..a4e6d4c 100644 --- a/doc/tipps-und-troubleshooting.md +++ b/doc/tipps-und-troubleshooting.md @@ -213,11 +213,18 @@ sudo bash install.sh update ## Deinstallation +Ab Version 0.6 gibt es einen eigenständigen Uninstaller im Installationsverzeichnis. Die Deinstallation kann daher jederzeit durchgeführt werden, **ohne die originalen Installationsdateien (install.sh) behalten zu müssen**: + ```bash -# Über den Installer (interaktiv mit Menü) +# Empfohlen: direkt aus dem Installationsverzeichnis ausführen +sudo bash /opt/adguard-shield/uninstall.sh + +# Alternativ: über den Installer (sofern noch vorhanden) sudo bash install.sh uninstall ``` +Beide Wege sind gleichwertig — `install.sh uninstall` delegiert intern an `/opt/adguard-shield/uninstall.sh`. + Oder manuell: ```bash sudo systemctl stop adguard-shield diff --git a/install.sh b/install.sh index 84e5ee0..928ff78 100644 --- a/install.sh +++ b/install.sh @@ -70,6 +70,9 @@ print_help() { echo -e " ${GREEN}uninstall${NC} Vollständige Deinstallation" echo -e " Stoppt den Service, entfernt iptables-Regeln und" echo -e " löscht alle Dateien (optional Konfiguration behalten)." + echo -e " Delegiert automatisch an den im Installationsverzeichnis" + echo -e " liegenden Uninstaller — kein Behalten der Installationsdateien nötig." + echo -e " Direkt ausführbar: ${CYAN}sudo bash $INSTALL_DIR/uninstall.sh${NC}" echo "" echo -e " ${GREEN}status${NC} Installationsstatus anzeigen" echo -e " Zeigt ob AdGuard Shield installiert ist, welche Version" @@ -239,6 +242,7 @@ install_files() { cp "$SCRIPT_DIR/unban-expired.sh" "$INSTALL_DIR/" cp "$SCRIPT_DIR/external-blocklist-worker.sh" "$INSTALL_DIR/" cp "$SCRIPT_DIR/report-generator.sh" "$INSTALL_DIR/" + cp "$SCRIPT_DIR/uninstall.sh" "$INSTALL_DIR/" # Templates kopieren mkdir -p "$INSTALL_DIR/templates" @@ -251,6 +255,7 @@ install_files() { chmod +x "$INSTALL_DIR/unban-expired.sh" chmod +x "$INSTALL_DIR/external-blocklist-worker.sh" chmod +x "$INSTALL_DIR/report-generator.sh" + chmod +x "$INSTALL_DIR/uninstall.sh" echo -e " ✅ Dateien installiert" echo "" @@ -519,6 +524,9 @@ print_summary() { echo " Hilfe anzeigen:" echo " sudo bash install.sh --help" echo "" + echo " Deinstallieren (auch ohne Installationsdateien):" + echo " sudo bash $INSTALL_DIR/uninstall.sh" + echo "" } # ─── Status anzeigen ───────────────────────────────────────────────────────── @@ -705,10 +713,15 @@ do_uninstall() { exit 1 fi - echo -e "${YELLOW}Deinstalliere AdGuard Shield...${NC}" + # An den im Installationsverzeichnis liegenden Uninstaller delegieren + if [[ -f "$INSTALL_DIR/uninstall.sh" ]]; then + exec bash "$INSTALL_DIR/uninstall.sh" + fi + + # Fallback für ältere Installationen ohne uninstall.sh + echo -e "${YELLOW}Deinstalliere AdGuard Shield (Fallback-Modus)...${NC}" echo "" - # Sicherheitsabfrage read -rep " Wirklich deinstallieren? [j/N]: " confirm if [[ "${confirm,,}" != "j" ]]; then echo -e "${GREEN}Deinstallation abgebrochen.${NC}" @@ -716,7 +729,6 @@ do_uninstall() { fi echo "" - # Service stoppen und deaktivieren if systemctl is-active adguard-shield &>/dev/null; then systemctl stop adguard-shield echo " ✅ Service gestoppt" @@ -729,18 +741,18 @@ do_uninstall() { systemctl daemon-reload echo " ✅ Service-Datei entfernt" - # iptables Chain aufräumen if [[ -f "$INSTALL_DIR/iptables-helper.sh" ]]; then bash "$INSTALL_DIR/iptables-helper.sh" remove || true fi - # Dateien entfernen read -rep " Konfiguration und Logs behalten? [j/N]: " keep if [[ "${keep,,}" == "j" ]]; then rm -f "$INSTALL_DIR/adguard-shield.sh" rm -f "$INSTALL_DIR/iptables-helper.sh" rm -f "$INSTALL_DIR/unban-expired.sh" rm -f "$INSTALL_DIR/external-blocklist-worker.sh" + rm -f "$INSTALL_DIR/report-generator.sh" + rm -rf "$INSTALL_DIR/templates" echo " ✅ Scripts entfernt (Konfiguration und Logs behalten)" else rm -rf "$INSTALL_DIR" @@ -766,7 +778,7 @@ main() { do_update ;; uninstall) - print_header + # print_header wird vom delegierten uninstall.sh übernommen do_uninstall ;; status) diff --git a/uninstall.sh b/uninstall.sh new file mode 100644 index 0000000..a0c82b8 --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,129 @@ +#!/bin/bash +############################################################################### +# AdGuard Shield - Uninstaller +# Autor: Patrick Asmus +# E-Mail: support@techniverse.net +# Lizenz: MIT +# +# Dieses Script befindet sich im Installationsverzeichnis und kann daher +# ohne die originalen Installationsdateien ausgeführt werden: +# sudo bash /opt/adguard-shield/uninstall.sh +############################################################################### + +# INSTALL_DIR ergibt sich aus dem Verzeichnis, in dem dieses Script liegt +INSTALL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SERVICE_FILE="/etc/systemd/system/adguard-shield.service" + +# Farben +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +BOLD='\033[1m' +NC='\033[0m' + +print_header() { + echo "" + echo -e "${BLUE}" + echo " ▄▄▄ ▓█████▄ ▄████ █ ██ ▄▄▄ ██▀███ ▓█████▄ ██████ ██░ ██ ██▓▓█████ ██▓ ▓█████▄ " + echo "▒████▄ ▒██▀ ██▌ ██▒ ▀█▒ ██ ▓██▒▒████▄ ▓██ ▒ ██▒▒██▀ ██▌ ▒██ ▒ ▓██░ ██▒▓██▒▓█ ▀ ▓██▒ ▒██▀ ██▌" + echo "▒██ ▀█▄ ░██ █▌▒██░▄▄▄░▓██ ▒██░▒██ ▀█▄ ▓██ ░▄█ ▒░██ █▌ ░ ▓██▄ ▒██▀▀██░▒██▒▒███ ▒██░ ░██ █▌" + echo "░██▄▄▄▄██ ░▓█▄ ▌░▓█ ██▓▓▓█ ░██░░██▄▄▄▄██ ▒██▀▀█▄ ░▓█▄ ▌ ▒ ██▒░▓█ ░██ ░██░▒▓█ ▄ ▒██░ ░▓█▄ ▌" + echo " ▓█ ▓██▒░▒████▓ ░▒▓███▀▒▒▒█████▓ ▓█ ▓██▒░██▓ ▒██▒░▒████▓ ▒██████▒▒░▓█▒░██▓░██░░▒████▒░██████▒░▒████▓ " + echo " ▒▒ ▓▒█░ ▒▒▓ ▒ ░▒ ▒ ░▒▓▒ ▒ ▒ ▒▒ ▓▒█░░ ▒▓ ░▒▓░ ▒▒▓ ▒ ▒ ▒▓▒ ▒ ░ ▒ ░░▒░▒░▓ ░░ ▒░ ░░ ▒░▓ ░ ▒▒▓ ▒ " + echo " ▒ ▒▒ ░ ░ ▒ ▒ ░ ░ ░░▒░ ░ ░ ▒ ▒▒ ░ ░▒ ░ ▒░ ░ ▒ ▒ ░ ░▒ ░ ░ ▒ ░▒░ ░ ▒ ░ ░ ░ ░░ ░ ▒ ░ ░ ▒ ▒ " + echo " ░ ▒ ░ ░ ░ ░ ░ ░ ░░░ ░ ░ ░ ▒ ░░ ░ ░ ░ ░ ░ ░ ░ ░ ░░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ " + echo " ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ " + echo " ░ ░ ░ " + echo -e "${NC}" + echo -e "${GREEN} Uninstaller${NC}" + echo -e "${BLUE} Autor: Patrick Asmus${NC}" + echo -e + echo -e "${BLUE} E-Mail: support@techniverse.net${NC}" + echo -e "${BLUE} Web: https://www.patrick-asmus.de${NC}" + echo "" + echo -e "${BLUE}───────────────────────────────────────────────────────────────────────────────────────────────────────────────${NC}" + echo "" + echo -e "${BLUE} Repo: https://git.techniverse.net/scriptos/adguard-shield${NC}" + echo "" + echo -e "${BLUE}═══════════════════════════════════════════════════════════════════════════════════════════════════════════════${NC}" + echo "" +} + +check_root() { + if [[ $EUID -ne 0 ]]; then + echo -e "${RED}Dieses Script muss als root ausgeführt werden!${NC}" >&2 + echo "Bitte mit 'sudo $0' ausführen." + exit 1 + fi +} + +do_uninstall() { + check_root + + # Prüfen ob installiert + if [[ ! -d "$INSTALL_DIR" ]]; then + echo -e "${RED}AdGuard Shield ist nicht installiert (Verzeichnis nicht gefunden: $INSTALL_DIR)!${NC}" + exit 1 + fi + + echo -e "${YELLOW}Deinstalliere AdGuard Shield aus: ${BOLD}$INSTALL_DIR${NC}" + echo "" + + # Sicherheitsabfrage + read -rep " Wirklich deinstallieren? [j/N]: " confirm + if [[ "${confirm,,}" != "j" ]]; then + echo -e "${GREEN}Deinstallation abgebrochen.${NC}" + exit 0 + fi + echo "" + + # Service stoppen und deaktivieren + if systemctl is-active adguard-shield &>/dev/null; then + systemctl stop adguard-shield + echo " ✅ Service gestoppt" + fi + if systemctl is-enabled adguard-shield &>/dev/null; then + systemctl disable adguard-shield + echo " ✅ Service deaktiviert" + fi + if [[ -f "$SERVICE_FILE" ]]; then + rm -f "$SERVICE_FILE" + systemctl daemon-reload + echo " ✅ Service-Datei entfernt" + fi + + # iptables Chain aufräumen + if [[ -f "$INSTALL_DIR/iptables-helper.sh" ]]; then + bash "$INSTALL_DIR/iptables-helper.sh" remove || true + fi + + # Dateien entfernen + read -rep " Konfiguration und Logs behalten? [j/N]: " keep + if [[ "${keep,,}" == "j" ]]; then + rm -f "$INSTALL_DIR/adguard-shield.sh" + rm -f "$INSTALL_DIR/iptables-helper.sh" + rm -f "$INSTALL_DIR/unban-expired.sh" + rm -f "$INSTALL_DIR/external-blocklist-worker.sh" + rm -f "$INSTALL_DIR/report-generator.sh" + rm -f "$INSTALL_DIR/uninstall.sh" + rm -rf "$INSTALL_DIR/templates" + echo " ✅ Scripts entfernt (Konfiguration und Logs behalten)" + echo "" + echo -e "${YELLOW} Konfiguration verbleibt in: $INSTALL_DIR/adguard-shield.conf${NC}" + echo -e "${YELLOW} Logs verbleiben in: /var/log/adguard-shield*.log${NC}" + else + rm -rf "$INSTALL_DIR" + rm -rf /var/lib/adguard-shield + rm -f /var/log/adguard-shield.log* + rm -f /var/log/adguard-shield-bans.log + echo " ✅ Alles entfernt" + fi + + echo "" + echo -e "${GREEN}Deinstallation abgeschlossen.${NC}" +} + +print_header +do_uninstall From 007c2b01bce9f63767f568afd37037b77b3471e3 Mon Sep 17 00:00:00 2001 From: scriptos Date: Fri, 6 Mar 2026 13:13:32 +0100 Subject: [PATCH 3/3] Release v0.5.2 --- adguard-shield.sh | 2 +- install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/adguard-shield.sh b/adguard-shield.sh index d9c1a2c..8ca30bf 100644 --- a/adguard-shield.sh +++ b/adguard-shield.sh @@ -9,7 +9,7 @@ # Lizenz: MIT ############################################################################### -VERSION="v0.5.1" +VERSION="v0.5.2" set -euo pipefail diff --git a/install.sh b/install.sh index 928ff78..d0b756a 100644 --- a/install.sh +++ b/install.sh @@ -6,7 +6,7 @@ # Lizenz: MIT ############################################################################### -VERSION="v0.5.1" +VERSION="v0.5.2" set -euo pipefail