package adapters import ( "context" "fmt" "github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common/i18n" "github.com/shadow1ng/fscan/common/output" "github.com/shadow1ng/fscan/plugins/base" "time" // 导入新插件以触发注册 _ "github.com/shadow1ng/fscan/plugins/services/mysql" _ "github.com/shadow1ng/fscan/plugins/services/redis" _ "github.com/shadow1ng/fscan/plugins/services/ssh" ) // PluginAdapter 插件适配器,将新插件架构与旧系统集成 type PluginAdapter struct { registry *base.PluginRegistry } // NewPluginAdapter 创建插件适配器 func NewPluginAdapter() *PluginAdapter { return &PluginAdapter{ registry: base.GlobalPluginRegistry, } } // AdaptPluginScan 适配插件扫描调用 // 将传统的插件扫描函数调用转换为新架构的插件调用 func (a *PluginAdapter) AdaptPluginScan(pluginName string, info *common.HostInfo) error { // 创建插件实例 plugin, err := a.registry.Create(pluginName) if err != nil { // 如果新架构中没有该插件,返回错误让旧系统处理 return fmt.Errorf("plugin %s not found in new architecture: %v", pluginName, err) } // 初始化插件 if err := plugin.Initialize(); err != nil { return fmt.Errorf("plugin %s initialization failed: %v", pluginName, err) } // 设置全局超时上下文 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(common.GlobalTimeout)*time.Second) defer cancel() // 执行扫描 result, err := plugin.Scan(ctx, info) if err != nil { common.LogError(fmt.Sprintf("Plugin %s scan failed: %v", pluginName, err)) return err } // 如果扫描成功,记录结果 if result != nil && result.Success { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) // 适配器层不输出扫描结果,由插件层负责输出 // 这避免了重复输出的问题 common.LogDebug(fmt.Sprintf("插件 %s 适配成功: %s", pluginName, target)) // 保存结果到文件 a.saveResult(info, result, pluginName) // 如果有漏洞信息,也记录下来 for _, vuln := range result.Vulnerabilities { common.LogError(fmt.Sprintf("%s vulnerability found: %s - %s", pluginName, vuln.ID, vuln.Description)) } } return nil } // saveResult 保存扫描结果 func (a *PluginAdapter) saveResult(info *common.HostInfo, result *base.ScanResult, pluginName string) { // 使用原有的结果保存机制 vulnResult := &output.ScanResult{ Time: time.Now(), Type: output.TypeVuln, Target: info.Host, Status: "vulnerable", Details: map[string]interface{}{ "plugin": pluginName, "port": info.Ports, "host": info.Host, }, } if len(result.Credentials) > 0 { cred := result.Credentials[0] if cred.Username != "" { vulnResult.Details["username"] = cred.Username vulnResult.Details["password"] = cred.Password vulnResult.Details["credentials"] = fmt.Sprintf("%s:%s", cred.Username, cred.Password) } else { vulnResult.Details["password"] = cred.Password vulnResult.Details["credentials"] = cred.Password } } else { // 未授权访问 vulnResult.Details["type"] = "unauthorized" } // 保存结果 common.SaveResult(vulnResult) } // IsPluginSupported 检查插件是否在新架构中支持 func (a *PluginAdapter) IsPluginSupported(pluginName string) bool { plugins := a.registry.GetAll() for _, name := range plugins { if name == pluginName { return true } } return false } // GetSupportedPlugins 获取新架构支持的插件列表 func (a *PluginAdapter) GetSupportedPlugins() []string { return a.registry.GetAll() } // GetPluginMetadata 获取插件元数据 func (a *PluginAdapter) GetPluginMetadata(pluginName string) (*base.PluginMetadata, error) { metadata := a.registry.GetMetadata(pluginName) if metadata == nil { return nil, fmt.Errorf("plugin %s not found", pluginName) } return metadata, nil } // ============================================================================= // 全局适配器实例 // ============================================================================= // GlobalAdapter 全局插件适配器实例 var GlobalAdapter = NewPluginAdapter() // ============================================================================= // 便捷函数 // ============================================================================= // TryNewArchitecture 尝试使用新架构执行插件扫描 // 如果新架构支持该插件,则使用新架构;否则返回false让调用方使用旧插件 func TryNewArchitecture(pluginName string, info *common.HostInfo) bool { if !GlobalAdapter.IsPluginSupported(pluginName) { common.LogDebug(i18n.GetText("plugin_legacy_using", pluginName)) return false } common.LogDebug(i18n.GetText("plugin_new_arch_trying", pluginName)) err := GlobalAdapter.AdaptPluginScan(pluginName, info) if err != nil { common.LogError(i18n.GetText("plugin_new_arch_fallback", pluginName, err)) return false } common.LogDebug(i18n.GetText("plugin_new_arch_success", pluginName)) return true }