From 2adbae8310babbeb38be1629505630825b5b510e Mon Sep 17 00:00:00 2001 From: wuko233 Date: Mon, 16 Feb 2026 21:11:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E7=99=BD=E5=90=8D?= =?UTF-8?q?=E5=8D=95=E7=AE=A1=E7=90=86=E5=99=A8=E4=BB=A5=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=92=8C=E8=BF=9B=E7=A8=8B=E7=9A=84=E7=99=BD?= =?UTF-8?q?=E5=90=8D=E5=8D=95=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/whitelist/manager.go | 130 ++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 internal/whitelist/manager.go diff --git a/internal/whitelist/manager.go b/internal/whitelist/manager.go new file mode 100644 index 0000000..de25ae9 --- /dev/null +++ b/internal/whitelist/manager.go @@ -0,0 +1,130 @@ +package whitelist + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + + "github.com/wuko233/sysmonitord/internal/config" +) + +type Manager struct { + mu sync.RWMutex + official config.OfficialConfig + user config.UserConfig + mergedIgnore []string +} + +func NewManager() *Manager { + return &Manager{ + official: config.OfficialConfig{ + WhitelistFiles: make(map[string][]string), + }, + user: config.UserConfig{ + SupplementFiles: make(map[string][]string), + SupplementProcesses: make(map[string]string), + }, + } +} + +func (m *Manager) UpdateConfig(official config.OfficialConfig, user config.UserConfig) { + m.mu.Lock() + defer m.mu.Unlock() + + m.official = official + m.user = user + + m.mergedIgnore = append([]string{}, m.official.IgnoredPaths...) + m.mergedIgnore = append(m.mergedIgnore, m.user.IgnoredPaths...) +} + +func (m *Manager) IsPathIgnored(path string) bool { + m.mu.RLock() + defer m.mu.RUnlock() + + path = filepath.Clean(path) + for _, ignore := range m.mergedIgnore { + if strings.HasPrefix(path, filepath.Clean(ignore)) { + return true + } + } + return false +} + +// CheckFileStatus 检查文件状态 +// 返回: isWhitelisted(是否在白名单), isValid(Hash是否匹配), err +func (m *Manager) CheckFileStatus(path string) (bool, bool, error) { + m.mu.Lock() + defer m.mu.Unlock() + + if m.IsPathIgnored((path)) { + return true, true, nil + } + + hashes, exists := m.official.WhitelistFiles[path] + if !exists { + hashes, exists = m.user.SupplementFiles[path] + } + if !exists { + return false, false, nil + } + + fileHash, err := CalculateFileHash(path) + if err != nil { + return true, false, fmt.Errorf("计算文件哈希失败: %v", err) + } + + for _, h := range hashes { + if strings.EqualFold(h, fmt.Sprintf("%v", fileHash)) { + return true, true, nil + } + } + + return true, false, nil +} + +func CalculateFileHash(filePath string) (string, error) { + file, err := os.Open(filePath) + + if err != nil { + return "", err + } + + defer file.Close() + + hash := sha256.New() + if _, err := io.Copy(hash, file); err != nil { + return "", err + } + + return hex.EncodeToString(hash.Sum(nil)), nil +} + +func (m *Manager) IsProcessAllowed(procName string, cmdLine string) bool { + m.mu.RLock() + defer m.mu.RUnlock() + + for _, p := range m.official.WhitelistProcesses { + if p == procName { + return true + } + } + + if _, ok := m.user.SupplementProcesses[procName]; ok { + return true + } + + return false +} + +func (m *Manager) GetAuditServerUrl() string { + m.mu.RLock() + defer m.mu.RUnlock() + + return m.user.AuditServerUrl +}