|
@@ -2,13 +2,16 @@ package admin
|
|
|
|
|
|
import (
|
|
|
"encoding/json"
|
|
|
+ "fmt"
|
|
|
"github.com/go-nunu/nunu-layout-advanced/internal/service"
|
|
|
"github.com/tidwall/gjson"
|
|
|
"go.uber.org/zap"
|
|
|
+ "strings"
|
|
|
)
|
|
|
|
|
|
type WafLogDataCleanService interface {
|
|
|
ParseWafLogExtraData(extraDataBytes json.RawMessage, apiName string) CleanedExtraData
|
|
|
+ FormatBackendList(backendList interface{}) string
|
|
|
}
|
|
|
func NewWafLogDataCleanService(
|
|
|
service *service.Service,
|
|
@@ -51,6 +54,10 @@ type CleanedExtraData struct {
|
|
|
HostID int64 `json:"hostId,omitempty"`
|
|
|
Proxy bool `json:"proxy,omitempty"`
|
|
|
IsHttps int `json:"isHttps,omitempty"`
|
|
|
+ RuleID []int64 `json:"ruleId,omitempty"`
|
|
|
+
|
|
|
+ // 其他字段
|
|
|
+ AllowAndDenyIps string `json:"allowAndDenyIps,omitempty"`
|
|
|
|
|
|
// 动态字段存储,用于存储任意其他字段
|
|
|
DynamicFields map[string]interface{} `json:"dynamicFields,omitempty"`
|
|
@@ -105,6 +112,8 @@ func (s *wafLogDataCleanService) extractWithGjson(jsonStr, apiName string, resul
|
|
|
"domain": {"domain", "data.domain", "host", "data.host", "hostname"},
|
|
|
"proxy": {"proxy", "data.proxy"},
|
|
|
"isHttps": {"isHttps", "data.isHttps"},
|
|
|
+ "ids": {"ids", "data.ids", "ruleIds", "data.ruleIds", "ruleId", "data.ruleId"},
|
|
|
+ "ip": {"ip","newIp","ips"},
|
|
|
}
|
|
|
|
|
|
// 提取基础字段
|
|
@@ -122,6 +131,11 @@ func (s *wafLogDataCleanService) extractWithGjson(jsonStr, apiName string, resul
|
|
|
result.Proxy = gjson.Get(jsonStr, s.getFirstValidPathName(jsonStr, paths)).Bool()
|
|
|
case "isHttps":
|
|
|
result.IsHttps = int(gjson.Get(jsonStr, s.getFirstValidPathName(jsonStr, paths)).Int())
|
|
|
+ case "ids":
|
|
|
+ result.RuleID = s.extractRuleIDs(jsonStr, paths)
|
|
|
+ case "ip":
|
|
|
+ result.AllowAndDenyIps = value
|
|
|
+
|
|
|
}
|
|
|
|
|
|
}
|
|
@@ -154,11 +168,46 @@ func (s *wafLogDataCleanService) getFirstValidPathName(jsonStr string, paths []s
|
|
|
return ""
|
|
|
}
|
|
|
|
|
|
+// extractRuleIDs 提取规则ID数组
|
|
|
+func (s *wafLogDataCleanService) extractRuleIDs(jsonStr string, paths []string) []int64 {
|
|
|
+ var ruleIDs []int64
|
|
|
+
|
|
|
+ for _, path := range paths {
|
|
|
+ ruleResult := gjson.Get(jsonStr, path)
|
|
|
+ if !ruleResult.Exists() {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ switch {
|
|
|
+ case ruleResult.IsArray():
|
|
|
+ // 如果是数组,遍历提取每个ID
|
|
|
+ ruleResult.ForEach(func(key, value gjson.Result) bool {
|
|
|
+ if id := value.Int(); id > 0 {
|
|
|
+ ruleIDs = append(ruleIDs, id)
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ })
|
|
|
+ default:
|
|
|
+ // 如果是单个值,添加到数组中
|
|
|
+ if id := ruleResult.Int(); id > 0 {
|
|
|
+ ruleIDs = append(ruleIDs, id)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 找到有效数据就退出
|
|
|
+ if len(ruleIDs) > 0 {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return ruleIDs
|
|
|
+}
|
|
|
+
|
|
|
// extractBackendListWithGjson 使用gjson智能提取后端列表
|
|
|
func (s *wafLogDataCleanService) extractBackendListWithGjson(jsonStr, apiName string, result *CleanedExtraData) {
|
|
|
// 定义可能的后端列表字段路径
|
|
|
backendPaths := []string{
|
|
|
- "backendList", "data.backendList", "backends", "data.backends",
|
|
|
+ "data.backendList", "backendList", "backends", "data.backends",
|
|
|
"backend_list", "data.backend_list", "servers", "data.servers",
|
|
|
"upstreams", "data.upstreams", "targets", "data.targets",
|
|
|
}
|
|
@@ -267,3 +316,67 @@ func (s *wafLogDataCleanService) extractDynamicFields(jsonStr string, result *Cl
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+// formatBackendList 格式化后端地址列表
|
|
|
+func (s *wafLogDataCleanService) FormatBackendList(backendList interface{}) string {
|
|
|
+ if backendList == nil {
|
|
|
+ return ""
|
|
|
+ }
|
|
|
+
|
|
|
+ switch v := backendList.(type) {
|
|
|
+ case string:
|
|
|
+ return v
|
|
|
+ case []string:
|
|
|
+ if len(v) == 0 {
|
|
|
+ return ""
|
|
|
+ }
|
|
|
+ return strings.Join(v, ", ")
|
|
|
+ case []int64:
|
|
|
+ // 处理 []int64 类型的数组(如 RuleId)
|
|
|
+ if len(v) == 0 {
|
|
|
+ return ""
|
|
|
+ }
|
|
|
+ var strList []string
|
|
|
+ for _, id := range v {
|
|
|
+ strList = append(strList, fmt.Sprintf("%d", id))
|
|
|
+ }
|
|
|
+ return strings.Join(strList, ", ")
|
|
|
+ case []interface{}:
|
|
|
+ // 处理 []interface{} 类型的数组
|
|
|
+ if len(v) == 0 {
|
|
|
+ return ""
|
|
|
+ }
|
|
|
+ var strList []string
|
|
|
+ for _, item := range v {
|
|
|
+ if str := fmt.Sprintf("%v", item); str != "" && str != "<nil>" {
|
|
|
+ strList = append(strList, str)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return strings.Join(strList, ", ")
|
|
|
+ default:
|
|
|
+ // 对于其他类型,先转换为字符串再处理
|
|
|
+ str := fmt.Sprintf("%v", v)
|
|
|
+ // 处理 Go 数组格式 [item1 item2] -> item1, item2
|
|
|
+ if strings.HasPrefix(str, "[") && strings.HasSuffix(str, "]") {
|
|
|
+ // 移除方括号
|
|
|
+ content := strings.Trim(str, "[]")
|
|
|
+ if content != "" {
|
|
|
+ // 按空格分割并用逗号连接
|
|
|
+ parts := strings.Fields(content)
|
|
|
+ if len(parts) > 1 {
|
|
|
+ return strings.Join(parts, ", ")
|
|
|
+ }
|
|
|
+ return content
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 处理其他包含空格的字符串
|
|
|
+ if strings.Contains(str, " ") && !strings.Contains(str, "\n") {
|
|
|
+ parts := strings.Fields(str)
|
|
|
+ if len(parts) > 1 {
|
|
|
+ return strings.Join(parts, ", ")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return str
|
|
|
+ }
|
|
|
+}
|