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() return m.IsPathIgnoredUnsafe(path) } func (m *Manager) IsPathIgnoredUnsafe(path string) bool { 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.RLock() defer m.mu.RUnlock() if m.IsPathIgnoredUnsafe((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 }