use std::sync::atomic::{AtomicBool, Ordering}; static VT_ENABLED: AtomicBool = AtomicBool::new(false); /// Initialisiert die Windows-Konsole: /// - Setzt Code-Page 65001 (UTF-8) fΓΌr Ein- und Ausgabe (verhindert Umlaut-Fehler wie `fβ”œβ•r`) /// - Aktiviert VIRTUAL_TERMINAL_PROCESSING fΓΌr saubere ANSI-Farb- und Escape-Sequenz-Darstellung #[cfg(windows)] pub fn init_console() { const CP_UTF8: u32 = 65001; const STD_OUTPUT_HANDLE: u32 = 0xFFFFFFF5; // (DWORD)-11 const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x0004; extern "system" { fn SetConsoleOutputCP(wCodePageID: u32) -> i32; fn SetConsoleCP(wCodePageID: u32) -> i32; fn GetStdHandle(nStdHandle: u32) -> *mut std::ffi::c_void; fn GetConsoleMode(hConsoleHandle: *mut std::ffi::c_void, lpMode: *mut u32) -> i32; fn SetConsoleMode(hConsoleHandle: *mut std::ffi::c_void, dwMode: u32) -> i32; } unsafe { let _ = SetConsoleOutputCP(CP_UTF8); let _ = SetConsoleCP(CP_UTF8); let handle = GetStdHandle(STD_OUTPUT_HANDLE); if !handle.is_null() && handle as isize != -1 { let mut mode: u32 = 0; if GetConsoleMode(handle, &mut mode) != 0 { if SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0 { VT_ENABLED.store(true, Ordering::Relaxed); } } } } } #[cfg(not(windows))] pub fn init_console() { VT_ENABLED.store(true, Ordering::Relaxed); } pub fn is_vt_enabled() -> bool { VT_ENABLED.load(Ordering::Relaxed) } pub fn bold(s: &str) -> String { if is_vt_enabled() { format!("\x1b[1m{s}\x1b[0m") } else { s.to_string() } } pub fn dim(s: &str) -> String { if is_vt_enabled() { format!("\x1b[90m{s}\x1b[0m") } else { s.to_string() } } pub fn green(s: &str) -> String { if is_vt_enabled() { format!("\x1b[1;32m{s}\x1b[0m") } else { s.to_string() } } pub fn cyan(s: &str) -> String { if is_vt_enabled() { format!("\x1b[1;36m{s}\x1b[0m") } else { s.to_string() } } pub fn yellow(s: &str) -> String { if is_vt_enabled() { format!("\x1b[1;33m{s}\x1b[0m") } else { s.to_string() } } pub fn red(s: &str) -> String { if is_vt_enabled() { format!("\x1b[1;31m{s}\x1b[0m") } else { s.to_string() } } pub fn magenta(s: &str) -> String { if is_vt_enabled() { format!("\x1b[1;35m{s}\x1b[0m") } else { s.to_string() } } /// Gibt einen formatierten Fortschrittsschritt aus: ` [1/4] πŸ“¦ Schrittbeschreibung...` pub fn step(num: u8, total: u8, icon: &str, msg: &str) { let tag = cyan(&format!("[{}/{}]", num, total)); println!(" {} {} {}", tag, icon, msg); } /// Gibt den 24-Wort BIP-39 Notfall-WiederherstellungsschlΓΌssel in einer hervorgehobenen Sicherheitsbox aus. pub fn print_recovery_phrase_card(phrase: &str) { let words: Vec<&str> = phrase.split_whitespace().collect(); println!(); println!("{}", yellow("β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”")); println!("{}", yellow("β”‚ ⚠️ 24-WORT NOTFALL-WIEDERHERSTELLUNGSSCHLÜSSEL β”‚")); println!("{}", yellow("β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€")); println!("β”‚ Falls Sie Ihr Master-Passwort vergessen oder der Header β”‚"); println!("β”‚ beschΓ€digt wird, ist dies Ihre EINZIGE Rettung! β”‚"); println!("β”‚ Notieren Sie die WΓΆrter in EXAKTER Reihenfolge auf Papier! β”‚"); println!("{}", yellow("β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€")); for row in 0..8 { let w1 = if row < words.len() { format!("{:2}. {:<11}", row + 1, words[row]) } else { "".to_string() }; let w2 = if row + 8 < words.len() { format!("{:2}. {:<11}", row + 9, words[row + 8]) } else { "".to_string() }; let w3 = if row + 16 < words.len() { format!("{:2}. {:<11}", row + 17, words[row + 16]) } else { "".to_string() }; println!("β”‚ {:<18} {:<18} {:<18} β”‚", cyan(&w1), cyan(&w2), cyan(&w3)); } println!("{}", yellow("β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜")); println!(); } /// Gibt den detaillierten Bericht einer Container-IntegritΓ€tsprΓΌfung aus. pub fn print_verification_report(report: &crate::verify::VerificationReport) { println!(); println!("β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”"); println!("β”‚ Sanctum Container-IntegritΓ€tsprΓΌfung (FSCK) β”‚"); println!("β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜"); println!(" Container: {}", report.container_path); println!(" Format: Version {}", report.format_version); println!(); let sqlite_status = if report.sqlite_ok { green("βœ” OK") } else { red("βœ– FEHLER") }; let header_status = if report.header_ok { green("βœ” OK") } else { red("βœ– BESCHΓ„DIGT") }; let tree_status = if report.orphan_nodes == 0 { green("βœ” KONSISTENT") } else { red("βœ– INKONSISTENT") }; let chunk_status = if report.corrupted_chunks == 0 { green("βœ” AUTHENTIFIZIERT") } else { red("βœ– BESCHΓ„DIGT") }; println!(" β€’ SQLite B-Tree IntegritΓ€t: {}", sqlite_status); println!(" β€’ Header & KDF-Metadaten: {}", header_status); println!(" β€’ Verzeichnisbaum & Inodes: {}", tree_status); println!(" β€’ AEAD Chunk-AuthentizitΓ€t: {}", chunk_status); println!(); println!(" Statistiken:"); println!(" - Ordner: {}", report.total_dirs); println!(" - Dateien: {}", report.total_files); println!(" - Daten-Chunks: {}", report.total_chunks); if report.total_bytes_decrypted > 0 { let mb = report.total_bytes_decrypted as f64 / (1024.0 * 1024.0); println!(" - Verifiziert: {:.2} MB (vollstΓ€ndig entschlΓΌsselt)", mb); } if !report.errors.is_empty() { println!(); println!("{}", red(" Gefundene Probleme / Fehler:")); for err in &report.errors { println!(" {} {}", red("βœ–"), err); } } println!(); if report.is_healthy() { println!(" {}", green("βœ” Keine BeschΓ€digungen oder Bitrot festgestellt. Der Container ist integer.")); } else { println!(" {}", red("βœ– ACHTUNG: Der Container weist BeschΓ€digungen auf! Bitte Backup prΓΌfen.")); } println!(); }