Files
fscan/plugins/local/cleaner.go
T
ZacharyZcR 231563e82b fix: 修复 socks5proxy/cleaner/minidump 三个插件问题
- socks5proxy: 监听地址从 127.0.0.1 改为 0.0.0.0,允许外部连接
- cleaner: 重写清理逻辑,精准匹配 fscan 产物,修复 glob 遍历大目录卡死问题,
  history 清理改为真正删除 fscan 相关行
- minidump: SeDebugPrivilege 提升失败时直接退出,不再卡 120 秒超时
2026-05-16 03:17:44 +08:00

149 lines
3.6 KiB
Go

//go:build (plugin_cleaner || !plugin_selective) && !no_local
package local
import (
"context"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/common/i18n"
"github.com/shadow1ng/fscan/plugins"
)
type CleanerPlugin struct {
plugins.BasePlugin
}
func NewCleanerPlugin() *CleanerPlugin {
return &CleanerPlugin{BasePlugin: plugins.NewBasePlugin("cleaner")}
}
func (p *CleanerPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
var output strings.Builder
var cleaned int
// 清理工作目录下的 fscan 产物
workDir, _ := os.Getwd()
cleaned += p.cleanFiles(&output, workDir, []string{
"result.txt", "result.json", "result.csv",
"fscan_debug.log",
})
// 清理临时目录
cleaned += p.cleanGlob(&output, os.TempDir(), "fscan_*")
// 清理自身可执行文件(如果在工作目录)
if exe, err := os.Executable(); err == nil {
base := filepath.Base(exe)
if strings.Contains(strings.ToLower(base), "fscan") && filepath.Dir(exe) == workDir {
cleaned += p.cleanFiles(&output, workDir, []string{base})
}
}
// 平台特定清理
switch runtime.GOOS {
case "windows":
cleaned += p.cleanWindows(&output)
case "linux", "darwin":
cleaned += p.cleanUnix(&output)
}
common.LogSuccess(i18n.Tr("cleaner_success", cleaned, 0))
return &plugins.Result{
Success: cleaned > 0,
Type: plugins.ResultTypeService,
Output: output.String(),
}
}
func (p *CleanerPlugin) cleanFiles(output *strings.Builder, dir string, names []string) int {
cleaned := 0
for _, name := range names {
path := filepath.Join(dir, name)
if err := os.Remove(path); err == nil {
output.WriteString(fmt.Sprintf("[清理] %s\n", path))
cleaned++
}
}
return cleaned
}
func (p *CleanerPlugin) cleanGlob(output *strings.Builder, dir, pattern string) int {
matches, _ := filepath.Glob(filepath.Join(dir, pattern))
cleaned := 0
for _, f := range matches {
if err := os.Remove(f); err == nil {
output.WriteString(fmt.Sprintf("[清理] %s\n", f))
cleaned++
}
}
return cleaned
}
func (p *CleanerPlugin) cleanWindows(output *strings.Builder) int {
cleaned := 0
// Prefetch 中的 fscan 记录
cleaned += p.cleanGlob(output, `C:\Windows\Prefetch`, "FSCAN*.pf")
// Recent 中的 fscan 快捷方式
if profile := os.Getenv("USERPROFILE"); profile != "" {
cleaned += p.cleanGlob(output, filepath.Join(profile, "Recent"), "fscan*.lnk")
}
return cleaned
}
func (p *CleanerPlugin) cleanUnix(output *strings.Builder) int {
cleaned := 0
homeDir, _ := os.UserHomeDir()
// 从 history 文件中删除 fscan 相关行
histFiles := []string{
filepath.Join(homeDir, ".bash_history"),
filepath.Join(homeDir, ".zsh_history"),
}
for _, hf := range histFiles {
if p.scrubHistory(hf) {
output.WriteString(fmt.Sprintf("[清理] %s 中的 fscan 记录\n", hf))
cleaned++
}
}
// /tmp 下的 fscan 残留
cleaned += p.cleanGlob(output, "/tmp", "fscan_*")
cleaned += p.cleanGlob(output, "/tmp", ".fscan*")
return cleaned
}
func (p *CleanerPlugin) scrubHistory(path string) bool {
data, err := os.ReadFile(path)
if err != nil {
return false
}
lines := strings.Split(string(data), "\n")
var kept []string
removed := false
for _, line := range lines {
if strings.Contains(strings.ToLower(line), "fscan") {
removed = true
continue
}
kept = append(kept, line)
}
if !removed {
return false
}
return os.WriteFile(path, []byte(strings.Join(kept, "\n")), 0600) == nil
}
func init() {
RegisterLocalPlugin("cleaner", func() Plugin {
return NewCleanerPlugin()
})
}