fscan/plugins/local/cleaner.go
ZacharyZcR 8f54702c02 refactor: 精准修复插件系统三个设计问题
经Linus式架构审计,发现并修复插件系统中的具体问题:

## 核心修复

### 1. 消除local插件GetPorts()方法冗余
- 删除21个local插件中无意义的GetPorts()方法
- 简化local.Plugin接口:移除端口概念
- 理由:本地插件不涉及网络,端口概念完全多余

### 2. 消除web插件GetPorts()方法冗余
- 删除2个web插件中无用的GetPorts()方法
- 简化web.WebPlugin接口:专注智能HTTP检测
- 理由:Web插件使用动态HTTP检测,预定义端口无价值

### 3. 统一插件命名规范
- 统一所有插件接口使用Name()方法(符合Go惯例)
- 消除GetName()与Name()不一致问题
- 简化适配器:不再需要方法名转换

## 技术改进

接口精简:
- local插件:GetName() + GetPorts() → Name()
- web插件:GetName() + GetPorts() → Name()
- services插件:GetName() → Name()(保留GetPorts(),业务必需)

代码减少:
- 删除23个无用GetPorts()方法
- 重命名52个Name()方法
- 简化3个插件接口定义

## 影响范围

修改文件:55个插件文件
代码变更:-155行 +61行(净减少94行)
功能影响:零破坏性,保持所有业务逻辑不变

这是基于业务需求分析的精准重构,消除真正多余的部分,
保持系统架构合理性和向后兼容性。
2025-08-26 20:38:39 +08:00

279 lines
6.7 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 local
import (
"context"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"github.com/shadow1ng/fscan/common"
)
// CleanerPlugin 系统痕迹清理插件 - Linus式简化版本
//
// 设计哲学:保持原有功能,删除过度设计
// - 删除复杂的继承体系和配置选项
// - 直接实现清理功能
// - 消除不必要的统计和报告结构
type CleanerPlugin struct {
name string
}
// NewCleanerPlugin 创建系统痕迹清理插件
func NewCleanerPlugin() *CleanerPlugin {
return &CleanerPlugin{
name: "cleaner",
}
}
// GetName 实现Plugin接口
func (p *CleanerPlugin) Name() string {
return p.name
}
// Scan 执行系统痕迹清理 - 直接、简单
func (p *CleanerPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult {
var output strings.Builder
var filesCleared, dirsCleared, sysCleared int
output.WriteString("=== 系统痕迹清理 ===\n")
// 清理当前目录fscan相关文件
workDir, _ := os.Getwd()
files := p.findFscanFiles(workDir)
for _, file := range files {
if p.removeFile(file) {
filesCleared++
output.WriteString(fmt.Sprintf("清理文件: %s\n", file))
}
}
// 清理临时目录fscan相关文件
tempFiles := p.findTempFiles()
for _, file := range tempFiles {
if p.removeFile(file) {
filesCleared++
output.WriteString(fmt.Sprintf("清理临时文件: %s\n", file))
}
}
// 清理日志和输出文件
logFiles := p.findLogFiles(workDir)
for _, file := range logFiles {
if p.removeFile(file) {
filesCleared++
output.WriteString(fmt.Sprintf("清理日志: %s\n", file))
}
}
// 平台特定清理
switch runtime.GOOS {
case "windows":
sysCleared += p.clearWindowsTraces()
case "linux", "darwin":
sysCleared += p.clearUnixTraces()
}
// 输出统计
output.WriteString(fmt.Sprintf("\n清理完成: 文件(%d) 目录(%d) 系统条目(%d)\n",
filesCleared, dirsCleared, sysCleared))
common.LogSuccess(fmt.Sprintf("痕迹清理完成: %d个文件, %d个系统条目", filesCleared, sysCleared))
return &ScanResult{
Success: filesCleared > 0 || sysCleared > 0,
Output: output.String(),
Error: nil,
}
}
// findFscanFiles 查找fscan相关文件 - 简化搜索逻辑
func (p *CleanerPlugin) findFscanFiles(dir string) []string {
var files []string
// fscan相关文件模式 - 直接硬编码
patterns := []string{
"fscan*.exe", "fscan*.log", "result*.txt", "result*.json",
"fscan_*", "*fscan*", "scan_result*", "vulnerability*",
}
for _, pattern := range patterns {
matches, _ := filepath.Glob(filepath.Join(dir, pattern))
files = append(files, matches...)
}
return files
}
// findTempFiles 查找临时文件
func (p *CleanerPlugin) findTempFiles() []string {
var files []string
tempDir := os.TempDir()
// 临时文件模式
patterns := []string{
"fscan_*", "scan_*", "tmp_scan*", "vulnerability_*",
}
for _, pattern := range patterns {
matches, _ := filepath.Glob(filepath.Join(tempDir, pattern))
files = append(files, matches...)
}
return files
}
// findLogFiles 查找日志文件
func (p *CleanerPlugin) findLogFiles(dir string) []string {
var files []string
// 日志文件模式
logPatterns := []string{
"*.log", "scan*.txt", "error*.txt", "debug*.txt",
"output*.txt", "report*.txt", "*.out",
}
for _, pattern := range logPatterns {
matches, _ := filepath.Glob(filepath.Join(dir, pattern))
for _, match := range matches {
// 只清理可能是扫描相关的日志
filename := strings.ToLower(filepath.Base(match))
if p.isScanRelatedLog(filename) {
files = append(files, match)
}
}
}
return files
}
// isScanRelatedLog 判断是否为扫描相关日志
func (p *CleanerPlugin) isScanRelatedLog(filename string) bool {
scanKeywords := []string{
"scan", "fscan", "vulnerability", "result", "report",
"exploit", "brute", "port", "service", "web",
}
for _, keyword := range scanKeywords {
if strings.Contains(filename, keyword) {
return true
}
}
return false
}
// clearWindowsTraces 清理Windows系统痕迹
func (p *CleanerPlugin) clearWindowsTraces() int {
cleared := 0
// 清理预读文件
prefetchDir := "C:\\Windows\\Prefetch"
if prefetchFiles := p.findPrefetchFiles(prefetchDir); len(prefetchFiles) > 0 {
for _, file := range prefetchFiles {
if p.removeFile(file) {
cleared++
}
}
}
// 清理最近文档记录(注册表方式复杂,这里简化处理)
// 可以通过删除Recent文件夹的快捷方式
if recentDir := os.Getenv("USERPROFILE") + "\\Recent"; p.dirExists(recentDir) {
recentFiles, _ := filepath.Glob(filepath.Join(recentDir, "fscan*.lnk"))
for _, file := range recentFiles {
if p.removeFile(file) {
cleared++
}
}
}
return cleared
}
// clearUnixTraces 清理Unix系统痕迹
func (p *CleanerPlugin) clearUnixTraces() int {
cleared := 0
// 清理bash历史记录相关
homeDir, _ := os.UserHomeDir()
historyFiles := []string{
filepath.Join(homeDir, ".bash_history"),
filepath.Join(homeDir, ".zsh_history"),
}
for _, histFile := range historyFiles {
if p.clearHistoryEntries(histFile) {
cleared++
}
}
// 清理/var/log中的相关日志需要权限
logDirs := []string{"/var/log", "/tmp"}
for _, logDir := range logDirs {
if p.dirExists(logDir) {
logFiles, _ := filepath.Glob(filepath.Join(logDir, "*fscan*"))
for _, file := range logFiles {
if p.removeFile(file) {
cleared++
}
}
}
}
return cleared
}
// findPrefetchFiles 查找预读文件
func (p *CleanerPlugin) findPrefetchFiles(dir string) []string {
var files []string
if !p.dirExists(dir) {
return files
}
matches, _ := filepath.Glob(filepath.Join(dir, "FSCAN*.pf"))
files = append(files, matches...)
return files
}
// clearHistoryEntries 清理历史记录条目(简化实现)
func (p *CleanerPlugin) clearHistoryEntries(histFile string) bool {
// 这里简化实现:不修改历史文件内容
// 实际应该是读取文件删除包含fscan的行然后写回
// 为简化,这里只记录找到相关历史文件
if p.fileExists(histFile) {
common.LogInfo(fmt.Sprintf("发现历史文件: %s (需手动清理相关条目)", histFile))
return true
}
return false
}
// removeFile 删除文件
func (p *CleanerPlugin) removeFile(path string) bool {
if err := os.Remove(path); err == nil {
return true
}
return false
}
// fileExists 检查文件是否存在
func (p *CleanerPlugin) fileExists(path string) bool {
_, err := os.Stat(path)
return err == nil
}
// dirExists 检查目录是否存在
func (p *CleanerPlugin) dirExists(path string) bool {
info, err := os.Stat(path)
return err == nil && info.IsDir()
}
// 注册插件
func init() {
RegisterLocalPlugin("cleaner", func() Plugin {
return NewCleanerPlugin()
})
}