mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00

- 完成Bridge.go中所有硬编码中文的i18n改造 - 修复Parse.go中的国际化消息调用格式 - 扩展i18n.go消息库至200+条完整消息覆盖 - 统一各子系统的多语言错误处理机制
281 lines
8.0 KiB
Go
281 lines
8.0 KiB
Go
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()
|
||
}
|