sysmonitord/internal/whitelist/manager.go

131 lines
2.5 KiB
Go

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
}