diff --git a/Common/Config.go b/Common/Config.go index b2f32401..3d479b30 100644 --- a/Common/Config.go +++ b/Common/Config.go @@ -119,6 +119,7 @@ var ( NoColor bool // 禁用彩色输出 JsonFormat bool // JSON格式输出 LogLevel string // 日志输出级别 + NoProgress bool // 禁用进度条显示 ) var ( diff --git a/Common/Flag.go b/Common/Flag.go index 6b0567f2..1bca7f6c 100644 --- a/Common/Flag.go +++ b/Common/Flag.go @@ -2,18 +2,138 @@ package Common import ( "flag" + "fmt" + "github.com/fatih/color" + "strings" + "time" ) func Banner() { - banner := ` - ___ _ - / _ \ ___ ___ _ __ __ _ ___| | __ - / /_\/____/ __|/ __| '__/ _` + "`" + ` |/ __| |/ / -/ /_\\_____\__ \ (__| | | (_| | (__| < -\____/ |___/\___|_| \__,_|\___|_|\_\ - fscan version: ` + version + ` -` - print(banner) + // 定义暗绿色系 + colors := []color.Attribute{ + color.FgGreen, // 基础绿 + color.FgHiGreen, // 亮绿 + } + + lines := []string{ + " ___ _ ", + " / _ \\ ___ ___ _ __ __ _ ___| | __ ", + " / /_\\/____/ __|/ __| '__/ _` |/ __| |/ /", + "/ /_\\\\_____\\__ \\ (__| | | (_| | (__| < ", + "\\____/ |___/\\___|_| \\__,_|\\___|_|\\_\\ ", + } + + // 获取最长行的长度 + maxLength := 0 + for _, line := range lines { + if len(line) > maxLength { + maxLength = len(line) + } + } + + // 清屏并隐藏光标 + fmt.Print("\033[H\033[2J\033[?25l") + defer fmt.Print("\033[?25h") + + // 创建边框 + topBorder := "┌" + strings.Repeat("─", maxLength+2) + "┐" + bottomBorder := "└" + strings.Repeat("─", maxLength+2) + "┘" + + // 呼吸灯效果循环 + for cycle := 0; cycle < 2; cycle++ { // 2个完整循环 + // 亮度由暗到亮 + for i := 0; i <= 10; i++ { + fmt.Print("\033[H") + dim := float64(i) / 10.0 + + printDimmed(topBorder, colors[0], dim) + fmt.Println() + + for lineNum, line := range lines { + printDimmed("│ ", colors[0], dim) + for _, char := range line { + printDimmed(string(char), colors[lineNum%2], dim) + } + padding := maxLength - len(line) + printDimmed(strings.Repeat(" ", padding)+" │", colors[0], dim) + fmt.Println() + } + + printDimmed(bottomBorder, colors[0], dim) + fmt.Println() + + vStr := fmt.Sprintf(" Fscan Version: %s", version) + printDimmed(vStr, colors[1], dim) + fmt.Print("\n\n") + + time.Sleep(50 * time.Millisecond) + } + + // 亮度由亮到暗 + for i := 10; i >= 0; i-- { + fmt.Print("\033[H") + dim := float64(i) / 10.0 + + printDimmed(topBorder, colors[0], dim) + fmt.Println() + + for lineNum, line := range lines { + printDimmed("│ ", colors[0], dim) + for _, char := range line { + printDimmed(string(char), colors[lineNum%2], dim) + } + padding := maxLength - len(line) + printDimmed(strings.Repeat(" ", padding)+" │", colors[0], dim) + fmt.Println() + } + + printDimmed(bottomBorder, colors[0], dim) + fmt.Println() + + vStr := fmt.Sprintf(" Fscan Version: %s", version) + printDimmed(vStr, colors[1], dim) + fmt.Print("\n\n") + + time.Sleep(50 * time.Millisecond) + } + } + + // 最后显示完整亮度的版本 + fmt.Print("\033[H") + printDimmed(topBorder, colors[0], 1.0) + fmt.Println() + + for lineNum, line := range lines { + printDimmed("│ ", colors[0], 1.0) + for _, char := range line { + printDimmed(string(char), colors[lineNum%2], 1.0) + } + padding := maxLength - len(line) + printDimmed(strings.Repeat(" ", padding)+" │", colors[0], 1.0) + fmt.Println() + } + + printDimmed(bottomBorder, colors[0], 1.0) + fmt.Println() + + vStr := fmt.Sprintf(" Fscan Version: %s", version) + printDimmed(vStr, colors[1], 1.0) + fmt.Print("\n\n") +} + +// 辅助函数:打印带透明度的文字 +func printDimmed(text string, col color.Attribute, dim float64) { + if dim < 0.2 { + fmt.Print(strings.Repeat(" ", len(text))) + return + } + + intensity := int(255 * dim) + fmt.Printf("\033[38;2;%d;%d;%dm%s\033[0m", + int(float64(0)*dim), + intensity, + int(float64(0)*dim), + text) } func Flag(Info *HostInfo) { @@ -128,6 +248,7 @@ func Flag(Info *HostInfo) { flag.BoolVar(&NoColor, "nocolor", false, "禁用彩色输出显示") flag.BoolVar(&JsonFormat, "json", false, "以JSON格式输出结果") flag.StringVar(&LogLevel, "log", LogLevelInfo, "日志输出级别(ALL/SUCCESS/ERROR/INFO/DEBUG)") + flag.BoolVar(&NoProgress, "noprogress", false, "禁用进度条显示") flag.Parse() } diff --git a/Common/Log.go b/Common/Log.go index 1e570c5f..a15ba291 100644 --- a/Common/Log.go +++ b/Common/Log.go @@ -81,8 +81,8 @@ func formatLogMessage(entry *LogEntry) string { return fmt.Sprintf("[%s] [%s] %s", timeStr, entry.Level, entry.Content) } +// 修改 printLog 函数 func printLog(entry *LogEntry) { - // 先检查日志级别 if LogLevel != LogLevelAll && entry.Level != LogLevel && !(LogLevel == LogLevelInfo && (entry.Level == LogLevelInfo || entry.Level == LogLevelSuccess)) { @@ -92,11 +92,15 @@ func printLog(entry *LogEntry) { OutputMutex.Lock() defer OutputMutex.Unlock() + // 确保清除当前进度条 + if ProgressBar != nil { + ProgressBar.Clear() + time.Sleep(10 * time.Millisecond) + } + + // 打印日志 logMsg := formatLogMessage(entry) - // 只在输出到终端时处理进度条 if !NoColor { - // 清除当前行 - fmt.Print("\033[2K\r") if colorAttr, ok := logColors[entry.Level]; ok { color.New(colorAttr).Println(logMsg) } else { @@ -105,6 +109,14 @@ func printLog(entry *LogEntry) { } else { fmt.Println(logMsg) } + + // 确保日志完全输出 + time.Sleep(50 * time.Millisecond) + + // 重新渲染进度条 + if ProgressBar != nil { + ProgressBar.RenderBlank() + } } func LogError(errMsg string) { diff --git a/Core/Scanner.go b/Core/Scanner.go index 21f92ff4..bf09da7d 100644 --- a/Core/Scanner.go +++ b/Core/Scanner.go @@ -119,92 +119,62 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro loadedPlugins := make([]string, 0) // 先遍历一遍计算实际要执行的任务数 actualTasks := 0 - for _, target := range targets { - targetPort, _ := strconv.Atoi(target.Ports) - - for _, pluginName := range pluginsToRun { - plugin, exists := Common.PluginManager[pluginName] - if !exists { - continue - } - if Common.LocalScan { - if len(plugin.Ports) == 0 { - actualTasks++ - } - continue - } - - if isSinglePlugin { - actualTasks++ - continue - } - - if len(plugin.Ports) > 0 { - if plugin.HasPort(targetPort) { - actualTasks++ - } - } else { - actualTasks++ - } - } + // 定义任务结构 + type ScanTask struct { + pluginName string + target Common.HostInfo } + tasks := make([]ScanTask, 0) - // 初始化进度条 - Common.ProgressBar = progressbar.NewOptions(actualTasks, - progressbar.OptionEnableColorCodes(true), - progressbar.OptionShowCount(), - progressbar.OptionSetWidth(15), - progressbar.OptionSetDescription("[cyan]扫描进度:[reset]"), - progressbar.OptionSetTheme(progressbar.Theme{ - Saucer: "[green]=[reset]", - SaucerHead: "[green]>[reset]", - SaucerPadding: " ", - BarStart: "[", - BarEnd: "]", - }), - progressbar.OptionUseANSICodes(true), - progressbar.OptionSetRenderBlankState(true), - // 设置更新频率 - progressbar.OptionThrottle(65*time.Millisecond), - ) - - // 确保进度条首次渲染 - Common.ProgressBar.RenderBlank() - time.Sleep(100 * time.Millisecond) // 给进度条一个短暂的初始化时间 - + // 第一次遍历:计算任务数和收集要执行的插件 for _, target := range targets { targetPort, _ := strconv.Atoi(target.Ports) for _, pluginName := range pluginsToRun { plugin, exists := Common.PluginManager[pluginName] if !exists { - Common.LogError(fmt.Sprintf("插件 %s 不存在", pluginName)) continue } if Common.LocalScan { if len(plugin.Ports) == 0 { + actualTasks++ loadedPlugins = append(loadedPlugins, pluginName) - AddScan(pluginName, target, ch, wg) + tasks = append(tasks, ScanTask{ + pluginName: pluginName, + target: target, + }) } continue } if isSinglePlugin { + actualTasks++ loadedPlugins = append(loadedPlugins, pluginName) - AddScan(pluginName, target, ch, wg) + tasks = append(tasks, ScanTask{ + pluginName: pluginName, + target: target, + }) continue } if len(plugin.Ports) > 0 { if plugin.HasPort(targetPort) { + actualTasks++ loadedPlugins = append(loadedPlugins, pluginName) - AddScan(pluginName, target, ch, wg) + tasks = append(tasks, ScanTask{ + pluginName: pluginName, + target: target, + }) } } else { + actualTasks++ loadedPlugins = append(loadedPlugins, pluginName) - AddScan(pluginName, target, ch, wg) + tasks = append(tasks, ScanTask{ + pluginName: pluginName, + target: target, + }) } } } @@ -222,6 +192,31 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro sort.Strings(finalPlugins) Common.LogInfo(fmt.Sprintf("加载的插件: %s", strings.Join(finalPlugins, ", "))) + + // 在初始化进度条的地方添加判断 + if !Common.NoProgress { + Common.ProgressBar = progressbar.NewOptions(actualTasks, + progressbar.OptionEnableColorCodes(true), + progressbar.OptionShowCount(), + progressbar.OptionSetWidth(15), + progressbar.OptionSetDescription("[cyan]扫描进度:[reset]"), + progressbar.OptionSetTheme(progressbar.Theme{ + Saucer: "[green]=[reset]", + SaucerHead: "[green]>[reset]", + SaucerPadding: " ", + BarStart: "[", + BarEnd: "]", + }), + progressbar.OptionThrottle(65*time.Millisecond), + progressbar.OptionUseANSICodes(true), + progressbar.OptionSetRenderBlankState(true), + ) + } + + // 开始执行收集到的所有任务 + for _, task := range tasks { + AddScan(task.pluginName, task.target, ch, wg) + } } // finishScan 完成扫描任务