feat: v2.1.0 — Systemd Timer + Performance Optimierungen
Neue Features: - install-timer / remove-timer Befehle - Tägliche automatische AUR-Scans via systemd - Cache-Status-Anzeige mit Alter und TTL - AUR-Score aus Paket-Info (Votes, Popularität, Maintainer) - Performance: ~7x schneller durch gecachte AUR-Prüfung - PKGBUILD-Analyse nur bei verbose oder IOC-Match Verbesserungen: - Keine False-Positives für offizielle Repo-Pakete - HedgeDoc 1931 IOCs live geladen - Journal-Logging für Timer-Scans
This commit is contained in:
+177
@@ -5,6 +5,9 @@ use tracing::{info, warn};
|
||||
|
||||
const ALPM_HOOK_PATH: &str = "/usr/share/libalpm/hooks/aegisaur-pre-install.hook";
|
||||
const HOOK_SCRIPT_PATH: &str = "/usr/share/libalpm/hooks/aegisaur-check.sh";
|
||||
const SYSTEMD_SERVICE_PATH: &str = "/etc/systemd/system/aegisaur-scan.service";
|
||||
const SYSTEMD_TIMER_PATH: &str = "/etc/systemd/system/aegisaur-scan.timer";
|
||||
const SYSTEMD_SCRIPT_PATH: &str = "/usr/local/bin/aegisaur-scan-daily";
|
||||
|
||||
/// Installiert den ALPM-Hook für Pre-Install-Checks
|
||||
pub fn install_alpm_hook() -> Result<()> {
|
||||
@@ -144,4 +147,178 @@ pub fn remove_alpm_hook() -> Result<()> {
|
||||
/// Prüft ob Hook installiert ist
|
||||
pub fn is_hook_installed() -> bool {
|
||||
Path::new(ALPM_HOOK_PATH).exists() && Path::new(HOOK_SCRIPT_PATH).exists()
|
||||
}
|
||||
|
||||
/// Installiert den Systemd-Timer für tägliche AUR-Scans
|
||||
pub fn install_systemd_timer() -> Result<()> {
|
||||
// Service-Datei: Führt aegisaur aus
|
||||
let service_content = r#"[Unit]
|
||||
Description=AegisAUR Daily AUR Security Scan
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/aegisaur-scan-daily
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
"#;
|
||||
|
||||
// Timer-Datei: Täglich um 03:00 Uhr
|
||||
let timer_content = r#"[Unit]
|
||||
Description=AegisAUR Daily Scan Timer
|
||||
|
||||
[Timer]
|
||||
OnCalendar=daily
|
||||
Persistent=true
|
||||
RandomizedDelaySec=3600
|
||||
Unit=aegisaur-scan.service
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
"#;
|
||||
|
||||
// Wrapper-Script: Führt scan-all aus und loggt Ergebnisse
|
||||
let script_content = r#"#!/bin/bash
|
||||
# AegisAUR Daily Scan Script
|
||||
# Wird vom systemd-timer aufgerufen
|
||||
|
||||
set -e
|
||||
|
||||
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
AUR_SCANNER="/usr/bin/aegisaur"
|
||||
|
||||
if [[ ! -x "$AUR_SCANNER" ]]; then
|
||||
echo "[$TIMESTAMP] AegisAUR nicht gefunden unter $AUR_SCANNER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[$TIMESTAMP] Starte AegisAUR täglichen Scan..."
|
||||
|
||||
# Cache aktualisieren
|
||||
echo "[$TIMESTAMP] Aktualisiere IOC-Cache..."
|
||||
$AUR_SCANNER check-ioc >/dev/null 2>&1
|
||||
|
||||
# Alle AUR-Pakete scannen
|
||||
echo "[$TIMESTAMP] Scanne alle AUR-Pakete..."
|
||||
RESULTS=$($AUR_SCANNER scan-all 2>&1)
|
||||
|
||||
# Zusammenfassung loggen
|
||||
THREAT_COUNT=$(echo "$RESULTS" | grep -c "IOC ERKANNT!" || true)
|
||||
WARN_COUNT=$(echo "$RESULTS" | grep -c "WARNUNG" || true)
|
||||
DANGER_COUNT=$(echo "$RESULTS" | grep -c "DANGEROUS" || true)
|
||||
|
||||
echo "[$TIMESTAMP] Scan abgeschlossen: $THREAT_COUNT IOCs, $WARN_COUNT Warnungen, $DANGER_COUNT Gefahren"
|
||||
|
||||
if [[ $THREAT_COUNT -gt 0 ]] || [[ $DANGER_COUNT -gt 0 ]]; then
|
||||
echo "[$TIMESTAMP] KRITISCHE BEDROHUNGEN GEFUNDEN:"
|
||||
echo "$RESULTS" | grep -E "🔴|🚨|DANGEROUS|IOC" || true
|
||||
|
||||
# Optional: Desktop-Benachrichtigung
|
||||
if command -v notify-send >/dev/null 2>&1; then
|
||||
notify-send -u critical "AegisAUR Alert" "$THREAT_COUNT IOC(s) und $DANGER_COUNT Gefahr(en) in AUR-Paketen gefunden!"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "[$TIMESTAMP] Täglicher Scan abgeschlossen."
|
||||
"#;
|
||||
|
||||
// Service-Datei schreiben
|
||||
info!("Schreibe Systemd Service: {}", SYSTEMD_SERVICE_PATH);
|
||||
let mut service_file = std::fs::File::create(SYSTEMD_SERVICE_PATH)
|
||||
.context("Konnte Systemd Service nicht erstellen (Root-Rechte nötig)")?;
|
||||
service_file.write_all(service_content.as_bytes())?;
|
||||
|
||||
// Timer-Datei schreiben
|
||||
info!("Schreibe Systemd Timer: {}", SYSTEMD_TIMER_PATH);
|
||||
let mut timer_file = std::fs::File::create(SYSTEMD_TIMER_PATH)
|
||||
.context("Konnte Systemd Timer nicht erstellen")?;
|
||||
timer_file.write_all(timer_content.as_bytes())?;
|
||||
|
||||
// Script schreiben
|
||||
info!("Schreibe Daily-Scan Script: {}", SYSTEMD_SCRIPT_PATH);
|
||||
let mut script_file = std::fs::File::create(SYSTEMD_SCRIPT_PATH)
|
||||
.context("Konnte Scan-Script nicht erstellen")?;
|
||||
script_file.write_all(script_content.as_bytes())?;
|
||||
|
||||
// Script executable machen
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let mut perms = std::fs::metadata(SYSTEMD_SCRIPT_PATH)?.permissions();
|
||||
perms.set_mode(0o755);
|
||||
std::fs::set_permissions(SYSTEMD_SCRIPT_PATH, perms)?;
|
||||
}
|
||||
|
||||
// Systemd neu laden und Timer starten
|
||||
info!("Aktiviere Systemd Timer...");
|
||||
let status = std::process::Command::new("systemctl")
|
||||
.args(["daemon-reload"])
|
||||
.status()
|
||||
.context("systemctl daemon-reload fehlgeschlagen")?;
|
||||
|
||||
if !status.success() {
|
||||
anyhow::bail!("systemctl daemon-reload fehlgeschlagen");
|
||||
}
|
||||
|
||||
let status = std::process::Command::new("systemctl")
|
||||
.args(["enable", "--now", "aegisaur-scan.timer"])
|
||||
.status()
|
||||
.context("systemctl enable fehlgeschlagen")?;
|
||||
|
||||
if !status.success() {
|
||||
anyhow::bail!("Konnte Timer nicht aktivieren");
|
||||
}
|
||||
|
||||
info!("Systemd Timer erfolgreich installiert und aktiviert");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Entfernt den Systemd-Timer
|
||||
pub fn remove_systemd_timer() -> Result<()> {
|
||||
info!("Entferne Systemd Timer...");
|
||||
|
||||
// Timer stoppen und deaktivieren
|
||||
let _ = std::process::Command::new("systemctl")
|
||||
.args(["stop", "aegisaur-scan.timer"])
|
||||
.status();
|
||||
|
||||
let _ = std::process::Command::new("systemctl")
|
||||
.args(["disable", "aegisaur-scan.timer"])
|
||||
.status();
|
||||
|
||||
// Dateien löschen
|
||||
if Path::new(SYSTEMD_SERVICE_PATH).exists() {
|
||||
std::fs::remove_file(SYSTEMD_SERVICE_PATH)
|
||||
.context("Konnte Service-Datei nicht löschen")?;
|
||||
info!("Service entfernt: {}", SYSTEMD_SERVICE_PATH);
|
||||
}
|
||||
|
||||
if Path::new(SYSTEMD_TIMER_PATH).exists() {
|
||||
std::fs::remove_file(SYSTEMD_TIMER_PATH)
|
||||
.context("Konnte Timer-Datei nicht löschen")?;
|
||||
info!("Timer entfernt: {}", SYSTEMD_TIMER_PATH);
|
||||
}
|
||||
|
||||
if Path::new(SYSTEMD_SCRIPT_PATH).exists() {
|
||||
std::fs::remove_file(SYSTEMD_SCRIPT_PATH)
|
||||
.context("Konnte Script nicht löschen")?;
|
||||
info!("Script entfernt: {}", SYSTEMD_SCRIPT_PATH);
|
||||
}
|
||||
|
||||
// Systemd neu laden
|
||||
let _ = std::process::Command::new("systemctl")
|
||||
.args(["daemon-reload"])
|
||||
.status();
|
||||
|
||||
info!("Systemd Timer erfolgreich entfernt");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Prüft ob Timer installiert ist
|
||||
pub fn is_timer_installed() -> bool {
|
||||
Path::new(SYSTEMD_TIMER_PATH).exists() && Path::new(SYSTEMD_SERVICE_PATH).exists()
|
||||
}
|
||||
Reference in New Issue
Block a user