fscan/Common/Bridge.go
ZacharyZcR f5843e486b 完善Common包i18n国际化支持,优化错误格式化
- 完成Bridge.go中所有硬编码中文的i18n改造
- 修复Parse.go中的国际化消息调用格式
- 扩展i18n.go消息库至200+条完整消息覆盖
- 统一各子系统的多语言错误处理机制
2025-08-05 20:58:01 +08:00

281 lines
8.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package Common
/*
Bridge.go - 统一桥接模块
将Config.go、Log.go、Output.go、Proxy.go的桥接功能合并到一个文件中
减少文件数量提高代码组织性。保持所有原有API的完全兼容性。
*/
import (
"context"
"crypto/tls"
"fmt"
"io"
"log"
"net"
"sync"
"time"
"github.com/fatih/color"
"github.com/schollz/progressbar/v3"
"github.com/shadow1ng/fscan/Common/config"
"github.com/shadow1ng/fscan/Common/logging"
"github.com/shadow1ng/fscan/Common/output"
"github.com/shadow1ng/fscan/Common/proxy"
)
// =============================================================================
// 配置桥接 (Config.go 功能)
// =============================================================================
var version = "2.0.2"
// 向后兼容的输出配置变量
var (
Outputfile string
OutputFormat string
ProgressBar *progressbar.ProgressBar
OutputMutex sync.Mutex
)
// PocInfo POC详细信息结构
type PocInfo = config.PocInfo
func syncOutputConfig() {
cfg := config.GetGlobalConfig()
if cfg != nil && cfg.Output != nil {
Outputfile = cfg.Output.Outputfile
OutputFormat = cfg.Output.OutputFormat
}
ProgressBar = config.GetGlobalProgressBar()
}
// =============================================================================
// 日志桥接 (Log.go 功能)
// =============================================================================
// 全局日志状态和变量
var (
status = logging.NewScanStatus()
Num, End int64
StartTime = time.Now()
globalLogger *logging.Logger
loggerOnce sync.Once
)
// 日志级别常量
const (
LogLevelAll = string(logging.LevelAll)
LogLevelError = string(logging.LevelError)
LogLevelBase = string(logging.LevelBase)
LogLevelInfo = string(logging.LevelInfo)
LogLevelSuccess = string(logging.LevelSuccess)
LogLevelDebug = string(logging.LevelDebug)
LogLevelInfoSuccess = string(logging.LevelInfoSuccess)
LogLevelBaseInfoSuccess = string(logging.LevelBaseInfoSuccess)
)
// 类型别名
type LogEntry = logging.LogEntry
type ScanStatus = logging.ScanStatus
type ProgressDisplay = logging.ProgressDisplay
func getGlobalLogger() *logging.Logger {
loggerOnce.Do(func() {
config := &logging.LoggerConfig{
Level: logging.LevelBaseInfoSuccess, EnableColor: !NoColor, SlowOutput: SlowLogOutput,
ShowProgress: true, StartTime: StartTime,
LevelColors: map[logging.LogLevel]color.Attribute{
logging.LevelError: color.FgBlue, logging.LevelBase: color.FgYellow,
logging.LevelInfo: color.FgGreen, logging.LevelSuccess: color.FgRed, logging.LevelDebug: color.FgWhite,
},
}
globalLogger = logging.NewLogger(config)
if ProgressBar != nil {
globalLogger.SetProgressBar(ProgressBar)
}
globalLogger.SetOutputMutex(&OutputMutex)
status = globalLogger.GetScanStatus()
})
return globalLogger
}
// 日志相关函数
func InitLogger() { log.SetOutput(io.Discard); getGlobalLogger().Initialize() }
func LogDebug(msg string) { getGlobalLogger().Debug(msg) }
func LogBase(msg string) { getGlobalLogger().Base(msg) }
func LogInfo(msg string) { getGlobalLogger().Info(msg) }
func LogSuccess(result string) { getGlobalLogger().Success(result) }
func LogError(errMsg string) { getGlobalLogger().Error(errMsg) }
func CheckErrs(err error) error { return logging.CheckErrs(err) }
// =============================================================================
// 输出桥接 (Output.go 功能)
// =============================================================================
// 全局输出管理器
var ResultOutput *OutputManager
type OutputManager struct{ manager *output.Manager }
type ResultType = output.ResultType
const (
HOST ResultType = output.TypeHost
PORT ResultType = output.TypePort
SERVICE ResultType = output.TypeService
VULN ResultType = output.TypeVuln
)
type ScanResult = output.ScanResult
func createOutputManager(outputPath, outputFormat string) (*OutputManager, error) {
var format output.OutputFormat
switch outputFormat {
case "txt":
format = output.FormatTXT
case "json":
format = output.FormatJSON
case "csv":
format = output.FormatCSV
default:
return nil, fmt.Errorf(GetText("output_format_invalid", outputFormat))
}
config := output.DefaultManagerConfig(outputPath, format)
manager, err := output.NewManager(config)
if err != nil {
return nil, err
}
return &OutputManager{manager: manager}, nil
}
// 输出相关函数
func InitOutput() error {
LogDebug(GetText("output_init_start"))
switch OutputFormat {
case "txt", "json", "csv":
default:
return fmt.Errorf(GetText("output_format_invalid", OutputFormat))
}
if Outputfile == "" {
return fmt.Errorf(GetText("output_path_empty"))
}
manager, err := createOutputManager(Outputfile, OutputFormat)
if err != nil {
LogDebug(GetText("output_init_failed", err))
return fmt.Errorf(GetText("output_init_failed", err))
}
ResultOutput = manager
output.SetGlobalManager(manager.manager)
LogDebug(GetText("output_init_success"))
return nil
}
func (om *OutputManager) saveResult(result *ScanResult) error {
if om.manager == nil {
return fmt.Errorf(GetText("output_not_init"))
}
LogDebug(GetText("output_saving_result", result.Type, result.Target))
return om.manager.SaveResult(result)
}
func SaveResult(result *ScanResult) error {
if ResultOutput == nil {
LogDebug(GetText("output_not_init"))
return fmt.Errorf(GetText("output_not_init"))
}
return ResultOutput.saveResult(result)
}
func CloseOutput() error {
if ResultOutput == nil {
return nil
}
LogDebug(GetText("output_closing"))
err := ResultOutput.manager.Close()
if err != nil {
return fmt.Errorf(GetText("output_close_failed", err))
}
LogDebug(GetText("output_closed"))
return nil
}
// =============================================================================
// 代理桥接 (Proxy.go 功能)
// =============================================================================
// 代理相关函数
func WrapperTcpWithTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
return proxy.DialContextWithProxy(ctx, network, address)
}
func WrapperTcpWithContext(ctx context.Context, network, address string) (net.Conn, error) {
return proxy.DialContextWithProxy(ctx, network, address)
}
func Socks5Dialer(forward *net.Dialer) (interface{}, error) {
if err := syncProxyConfig(); err != nil {
return nil, fmt.Errorf(GetText("socks5_create_failed", err))
}
manager := proxy.GetGlobalProxy()
dialer, err := manager.GetDialer()
if err != nil {
return nil, fmt.Errorf(GetText("socks5_create_failed", err))
}
return dialer, nil
}
func WrapperTlsWithContext(ctx context.Context, network, address string, tlsConfig *tls.Config) (net.Conn, error) {
if err := syncProxyConfig(); err != nil {
LogError(GetText("proxy_config_sync_failed", err.Error()))
}
conn, err := proxy.DialTLSContextWithProxy(ctx, network, address, tlsConfig)
if err != nil {
LogError(GetText("tls_conn_failed", err.Error()))
return nil, fmt.Errorf(GetText("tls_conn_failed", err))
}
return conn, nil
}
func syncProxyConfig() error {
var proxyURL string
if Socks5Proxy != "" {
proxyURL = Socks5Proxy
} else if HttpProxy != "" {
proxyURL = HttpProxy
}
if proxy.IsProxyEnabledGlobally() {
currentAddr := proxy.GetGlobalProxyAddress()
if (proxyURL == "" && currentAddr == "") ||
(proxyURL != "" && currentAddr != "" && (Socks5Proxy == currentAddr || HttpProxy == currentAddr)) {
return nil
}
}
if err := proxy.InitGlobalProxy(proxyURL); err != nil {
return fmt.Errorf(GetText("proxy_init_failed", err))
}
if proxyURL != "" {
LogBase(GetText("proxy_enabled", proxy.GetGlobalProxyType(), proxy.GetGlobalProxyAddress()))
} else {
LogBase(GetText("proxy_disabled"))
}
return nil
}
// =============================================================================
// 初始化函数
// =============================================================================
func init() {
config.SetGlobalVersion(version)
syncOutputConfig()
}