package service import ( "crypto/sha256" "encoding/hex" "strings" "time" "unicode/utf8" "kefu-cloud/server/internal/model" ) // NormalizeDeviceKey 规范化设备指纹:优先客户端 device_id;否则用 UA 摘要哈希兜底。 func NormalizeDeviceKey(deviceID, userAgent string) string { id := strings.TrimSpace(deviceID) if id != "" { if utf8.RuneCountInString(id) > 64 { id = string([]rune(id)[:64]) } return id } ua := strings.TrimSpace(userAgent) if ua == "" { return "" } sum := sha256.Sum256([]byte(strings.ToLower(ua))) return hex.EncodeToString(sum[:])[:32] } // IsBlacklisted 检查租户下 IP/设备是否在有效黑名单中。 func IsBlacklisted(tenantID uint, kind, value string) (bool, *model.BlacklistEntry) { value = strings.TrimSpace(value) if value == "" || (kind != "ip" && kind != "device") { return false, nil } now := time.Now() var entry model.BlacklistEntry err := model.DB. Where("tenant_id = ? AND kind = ? AND value = ?", tenantID, kind, value). Where("expires_at IS NULL OR expires_at > ?", now). Order("id desc"). First(&entry).Error if err != nil { return false, nil } return true, &entry } // CheckVisitorBlacklist 同时检查 IP 与设备。 func CheckVisitorBlacklist(tenantID uint, ip, deviceKey string) (blocked bool, kind string, reason string) { if ok, e := IsBlacklisted(tenantID, "ip", ip); ok { return true, "ip", e.Reason } if ok, e := IsBlacklisted(tenantID, "device", deviceKey); ok { return true, "device", e.Reason } return false, "", "" }