package main import ( "bufio" "fmt" "os" "strings" ) const appVersion = "1.5.0" // Цвета терминала (общие для всех модулей) const ( cReset = "\033[0m" cRed = "\033[0;31m" cGreen = "\033[0;32m" cYellow = "\033[1;33m" cBlue = "\033[0;34m" cCyan = "\033[0;36m" ) func main() { // Загружаем конфигурацию из /etc/auspex/auspex.env if err := loadConfig(); err != nil { // Файл не найден - выводим предупреждение fmt.Printf("⚠️ %v\n", err) fmt.Println("⚠️ Используются значения по умолчанию") fmt.Printf("💡 Создайте файл конфигурации: sudo mkdir -p /etc/auspex && sudo nano /etc/auspex/auspex.env\n\n") } // Если переданы аргументы — быстрый вызов if len(os.Args) > 1 { runByFlag(os.Args[1], os.Args[2:]) return } // Интерактивное меню showMenu() } func runByFlag(flag string, extraArgs []string) { switch flag { case "-ss": fmt.Printf("%s⚡ Auspex — Просмотр занятых портов (TUI)%s\n\n", cCyan, cReset) if err := runPortsView(); err != nil { fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err) os.Exit(1) } case "-c": fmt.Printf("%s🔐 Auspex — Проверка SSL сертификатов%s\n\n", cCyan, cReset) if err := runCertCheck(); err != nil { fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err) os.Exit(1) } case "-p": fmt.Printf("%s🌐 Auspex — Проверка доступности портов%s\n\n", cCyan, cReset) if err := runPortCheck(); err != nil { fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err) os.Exit(1) } case "-m": fmt.Printf("%s🔄 Auspex — Проверка совпадений Angie ↔ Docker%s\n\n", cCyan, cReset) clientFilter := "" if len(extraArgs) > 0 { clientFilter = extraArgs[0] } if err := runMatchCheck(clientFilter); err != nil { fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err) os.Exit(1) } case "-l": fmt.Printf("%s📝 Auspex — Проверка активности логов%s\n\n", cCyan, cReset) if err := runLogCheck(); err != nil { fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err) os.Exit(1) } case "-sv": fmt.Printf("%s🔧 Auspex — Проверка состояния служб%s\n\n", cCyan, cReset) if err := runServiceCheck(); err != nil { fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err) os.Exit(1) } case "-dc", "-d": fmt.Printf("%s🐳 Auspex — Проверка контейнеров Docker%s\n\n", cCyan, cReset) if err := runDockerCheck(); err != nil { fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err) os.Exit(1) } case "-w": fmt.Printf("%s🌍 Auspex — Проверка доступности сайтов (lynx)%s\n\n", cCyan, cReset) sid := "" if len(extraArgs) > 0 { sid = extraArgs[0] } if err := runWebCheck(sid); err != nil { fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err) os.Exit(1) } case "-fd": fmt.Printf("%s🗑️ Auspex — Удалённые-но-открытые файловые дескрипторы%s\n\n", cCyan, cReset) if err := runFDCheck(); err != nil { fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err) os.Exit(1) } case "-dt": if err := runDockerTUI(); err != nil { fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err) os.Exit(1) } case "-fw": if err := runFirewallTUI(); err != nil { fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err) os.Exit(1) } case "-au": category := "" if len(extraArgs) > 0 { category = extraArgs[0] } if err := runAudit(category); err != nil { fmt.Fprintf(os.Stderr, "Ошибка: %v\n", err) os.Exit(1) } case "-v", "--version": fmt.Printf("auspex v%s (%s)\n", appVersion, buildVariant) case "-h", "--help": printUsage() default: fmt.Fprintf(os.Stderr, "%sНеизвестный флаг: %s%s\n\n", cRed, flag, cReset) printUsage() os.Exit(1) } } func showMenu() { printBanner() reader := bufio.NewReader(os.Stdin) for { printMenuOptions() fmt.Printf("%s>>> %s", cGreen, cReset) input, _ := reader.ReadString('\n') input = strings.TrimSpace(input) switch input { case "1", "-ss", "ss": if err := runPortsView(); err != nil { fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset) } case "2", "-c", "c": if err := runCertCheck(); err != nil { fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset) } case "3", "-p", "p": if err := runPortCheck(); err != nil { fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset) } case "4", "-m", "m": fmt.Printf(" Имя клиента (Enter = все): ") clientInput, _ := reader.ReadString('\n') clientInput = strings.TrimSpace(clientInput) if err := runMatchCheck(clientInput); err != nil { fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset) } case "5", "-l", "l": if err := runLogCheck(); err != nil { fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset) } case "6", "-sv", "sv": if err := runServiceCheck(); err != nil { fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset) } case "7", "-dc", "-d", "dc", "d": if err := runDockerCheck(); err != nil { fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset) } case "8", "-w", "w": fmt.Printf(" SID: ") sidInput, _ := reader.ReadString('\n') sidInput = strings.TrimSpace(sidInput) if err := runWebCheck(sidInput); err != nil { fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset) } case "9", "-fd", "fd": if err := runFDCheck(); err != nil { fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset) } case "10", "-dt", "dt": if err := runDockerTUI(); err != nil { fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset) } case "11", "-fw", "fw": if err := runFirewallTUI(); err != nil { fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset) } case "12", "-au", "au": fmt.Printf(" Категория (Enter = все: systemd/nginx/docker/cert/disk/network/firewall): ") catInput, _ := reader.ReadString('\n') catInput = strings.TrimSpace(catInput) if err := runAudit(catInput); err != nil { fmt.Fprintf(os.Stderr, "%sОшибка: %v%s\n", cRed, err, cReset) } case "0", "q", "quit", "exit": fmt.Println("Выход.") return default: fmt.Printf("%sНеизвестная команда. Введите 1-11 или 0 для выхода.%s\n", cRed, cReset) } fmt.Println() // разделитель перед повторным показом меню } } // printMenuOptions выводит нумерованный список утилит и подсказку по флагам. // Вызывается заново после каждого действия — успешного или с ошибкой, // программа не завершается, а возвращается к выбору. func printMenuOptions() { fmt.Printf("%sВыберите утилиту:%s\n\n", cBlue, cReset) fmt.Printf(" %s1%s) %s-ss%s Просмотр занятых портов (TUI интерфейс)\n", cGreen, cReset, cCyan, cReset) fmt.Printf(" %s2%s) %s-c %s Проверка SSL сертификатов\n", cGreen, cReset, cCyan, cReset) fmt.Printf(" %s3%s) %s-p %s Проверка доступности портов (nginx upstream) [WAF]\n", cGreen, cReset, cCyan, cReset) fmt.Printf(" %s4%s) %s-m %s Проверка совпадений портов Angie ↔ Docker [WAF]\n", cGreen, cReset, cCyan, cReset) fmt.Printf(" %s5%s) %s-l %s Проверка активности логов (PostgreSQL) [WAF]\n", cGreen, cReset, cCyan, cReset) fmt.Printf(" %s6%s) %s-sv%s Проверка состояния служб (systemd)\n", cGreen, cReset, cCyan, cReset) fmt.Printf(" %s7%s) %s-dc%s Проверка контейнеров Docker\n", cGreen, cReset, cCyan, cReset) fmt.Printf(" %s8%s) %s-w %s Проверка доступности сайтов (lynx) [sid] [WAF]\n", cGreen, cReset, cCyan, cReset) fmt.Printf(" %s9%s) %s-fd%s Удалённые-но-открытые файловые дескрипторы\n", cGreen, cReset, cCyan, cReset) fmt.Printf(" %s10%s) %s-dt%s Docker Live — TUI (аналог lazydocker)\n", cGreen, cReset, cCyan, cReset) fmt.Printf(" %s11%s) %s-fw%s Firewall — TUI (ufw/nftables/iptables)\n", cGreen, cReset, cCyan, cReset) fmt.Printf(" %s12%s) %s-au%s Audit — комплексная диагностика [категория]\n", cGreen, cReset, cCyan, cReset) fmt.Printf(" %s0%s) Выход\n\n", cGreen, cReset) fmt.Printf("%sДля быстрого вызова: auspex <ключ>%s\n", cYellow, cReset) fmt.Printf("%sПример: auspex -ss | auspex -c | auspex -p | auspex -m [клиент] | auspex -l | auspex -sv | auspex -dc | auspex -w %s\n\n", cYellow, cReset) } func printBanner() { fmt.Printf(`%s █████╗ ██╗ ██╗███████╗██████╗ ███████╗██╗ ██╗ ██╔══██╗██║ ██║██╔════╝██╔══██╗██╔════╝╚██╗██╔╝ ███████║██║ ██║███████╗██████╔╝█████╗ ╚███╔╝ ██╔══██║██║ ██║╚════██║██╔═══╝ ██╔══╝ ██╔██╗ ██║ ██║╚██████╔╝███████║██║ ███████╗██╔╝ ██╗ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚══════╝╚═╝ ╚═╝ %s`, cCyan, cReset) fmt.Printf(" %sv%s%s — набор утилит мониторинга инфраструктуры\n", cBlue, appVersion, cReset) if buildHasWAF { fmt.Printf(" %sСборка: full (включает WAF-модули -p, -l, -m, -w)%s\n\n", cYellow, cReset) } else { fmt.Printf(" %sСборка: generic (без WAF-модулей -p, -l, -m, -w — см. -h)%s\n\n", cYellow, cReset) } } func printUsage() { fmt.Printf("Использование: auspex [флаг] [аргументы]\n\n") fmt.Printf("Флаги:\n") fmt.Printf(" %-12s Просмотр занятых портов (интерактивный TUI)\n", "-ss") fmt.Printf(" %-12s Проверка SSL сертификатов в %s\n", "-c", cfgSSLDir) fmt.Printf(" %-12s Проверка доступности портов (nginx upstream) [WAF]\n", "-p") fmt.Printf(" %-12s Проверка совпадений портов Angie ↔ Docker [имя_клиента] [WAF]\n", "-m") fmt.Printf(" %-12s Проверка активности логов (PostgreSQL) [WAF]\n", "-l") fmt.Printf(" %-12s Проверка состояния служб systemd\n", "-sv") fmt.Printf(" %-12s Проверка контейнеров Docker\n", "-dc") fmt.Printf(" %-12s Проверка доступности сайтов через lynx [sid] [WAF]\n", "-w") fmt.Printf(" %-12s Удалённые-но-открытые файловые дескрипторы (recover/reopen/restart/kill)\n", "-fd") fmt.Printf(" %-12s Docker Live — интерактивный TUI (аналог lazydocker)\n", "-dt") fmt.Printf(" %-12s Firewall — интерактивный TUI (ufw/nftables/iptables, dry-run 'D')\n", "-fw") fmt.Printf(" %-12s Комплексный аудит-скан по категориям [категория] (read-only)\n", "-au") fmt.Printf(" %-12s Показать версию\n", "-v") fmt.Printf(" %-12s Показать эту справку\n\n", "-h") fmt.Printf("Без аргументов запускается интерактивное меню.\n") if !buildHasWAF { fmt.Printf("\n%s⚠️ Эта сборка (generic) не включает модули [WAF] (-p, -m, -l, -w) —\n"+ " они требуют БД waf_info / структуры PT AF. Соберите с 'go build -tags waf .',\n"+ " чтобы получить полную (full) сборку.%s\n", cYellow, cReset) } }