浏览代码

add expr XML helpers (#1493)

blotus 3 年之前
父节点
当前提交
64369b5c2b
共有 5 个文件被更改,包括 201 次插入17 次删除
  1. 2 1
      go.mod
  2. 2 0
      go.sum
  3. 18 16
      pkg/exprhelpers/exprlib.go
  4. 64 0
      pkg/exprhelpers/xml.go
  5. 115 0
      pkg/exprhelpers/xml_test.go

+ 2 - 1
go.mod

@@ -16,9 +16,9 @@ require (
 	github.com/confluentinc/bincover v0.2.0
 	github.com/confluentinc/bincover v0.2.0
 	github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
 	github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
 	github.com/crowdsecurity/grokky v0.0.0-20220120093523-d5b3478363fa
 	github.com/crowdsecurity/grokky v0.0.0-20220120093523-d5b3478363fa
+	github.com/crowdsecurity/machineid v1.0.1
 	github.com/davecgh/go-spew v1.1.1
 	github.com/davecgh/go-spew v1.1.1
 	github.com/denisbrodbeck/machineid v1.0.1
 	github.com/denisbrodbeck/machineid v1.0.1
-	github.com/crowdsecurity/machineid v1.0.1
 	github.com/dghubble/sling v1.3.0
 	github.com/dghubble/sling v1.3.0
 	github.com/docker/docker v20.10.2+incompatible
 	github.com/docker/docker v20.10.2+incompatible
 	github.com/docker/go-connections v0.4.0
 	github.com/docker/go-connections v0.4.0
@@ -78,6 +78,7 @@ require (
 	github.com/ahmetalpbalkan/dlog v0.0.0-20170105205344-4fb5f8204f26 // indirect
 	github.com/ahmetalpbalkan/dlog v0.0.0-20170105205344-4fb5f8204f26 // indirect
 	github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
 	github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
 	github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect
 	github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect
+	github.com/beevik/etree v1.1.0 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cespare/xxhash/v2 v2.1.2 // indirect
 	github.com/cespare/xxhash/v2 v2.1.2 // indirect
 	github.com/containerd/containerd v1.6.2 // indirect
 	github.com/containerd/containerd v1.6.2 // indirect

+ 2 - 0
go.sum

@@ -97,6 +97,8 @@ github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:W
 github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
 github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
 github.com/aws/aws-sdk-go v1.42.25 h1:BbdvHAi+t9LRiaYUyd53noq9jcaAcfzOhSVbKfr6Avs=
 github.com/aws/aws-sdk-go v1.42.25 h1:BbdvHAi+t9LRiaYUyd53noq9jcaAcfzOhSVbKfr6Avs=
 github.com/aws/aws-sdk-go v1.42.25/go.mod h1:gyRszuZ/icHmHAVE4gc/r+cfCmhA1AD+vqfWbgI+eHs=
 github.com/aws/aws-sdk-go v1.42.25/go.mod h1:gyRszuZ/icHmHAVE4gc/r+cfCmhA1AD+vqfWbgI+eHs=
+github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
+github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=

+ 18 - 16
pkg/exprhelpers/exprlib.go

@@ -40,22 +40,24 @@ func Lower(s string) string {
 
 
 func GetExprEnv(ctx map[string]interface{}) map[string]interface{} {
 func GetExprEnv(ctx map[string]interface{}) map[string]interface{} {
 	var ExprLib = map[string]interface{}{
 	var ExprLib = map[string]interface{}{
-		"Atof":                Atof,
-		"JsonExtract":         JsonExtract,
-		"JsonExtractUnescape": JsonExtractUnescape,
-		"JsonExtractLib":      JsonExtractLib,
-		"File":                File,
-		"RegexpInFile":        RegexpInFile,
-		"Upper":               Upper,
-		"Lower":               Lower,
-		"IpInRange":           IpInRange,
-		"TimeNow":             TimeNow,
-		"ParseUri":            ParseUri,
-		"PathUnescape":        PathUnescape,
-		"QueryUnescape":       QueryUnescape,
-		"PathEscape":          PathEscape,
-		"QueryEscape":         QueryEscape,
-		"IpToRange":           IpToRange,
+		"Atof":                 Atof,
+		"JsonExtract":          JsonExtract,
+		"JsonExtractUnescape":  JsonExtractUnescape,
+		"JsonExtractLib":       JsonExtractLib,
+		"File":                 File,
+		"RegexpInFile":         RegexpInFile,
+		"Upper":                Upper,
+		"Lower":                Lower,
+		"IpInRange":            IpInRange,
+		"TimeNow":              TimeNow,
+		"ParseUri":             ParseUri,
+		"PathUnescape":         PathUnescape,
+		"QueryUnescape":        QueryUnescape,
+		"PathEscape":           PathEscape,
+		"QueryEscape":          QueryEscape,
+		"XMLGetAttributeValue": XMLGetAttributeValue,
+		"XMLGetNodeValue":      XMLGetNodeValue,
+		"IpToRange":            IpToRange,
 	}
 	}
 	for k, v := range ctx {
 	for k, v := range ctx {
 		ExprLib[k] = v
 		ExprLib[k] = v

+ 64 - 0
pkg/exprhelpers/xml.go

@@ -0,0 +1,64 @@
+package exprhelpers
+
+import (
+	"github.com/beevik/etree"
+	log "github.com/sirupsen/logrus"
+)
+
+var pathCache = make(map[string]etree.Path)
+
+func XMLGetAttributeValue(xmlString string, path string, attributeName string) string {
+
+	if _, ok := pathCache[path]; !ok {
+		compiledPath, err := etree.CompilePath(path)
+		if err != nil {
+			log.Errorf("Could not compile path %s: %s", path, err)
+			return ""
+		}
+		pathCache[path] = compiledPath
+	}
+
+	compiledPath := pathCache[path]
+	doc := etree.NewDocument()
+	err := doc.ReadFromString(xmlString)
+	if err != nil {
+		log.Tracef("Could not parse XML: %s", err)
+		return ""
+	}
+	elem := doc.FindElementPath(compiledPath)
+	if elem == nil {
+		log.Debugf("Could not find element %s", path)
+		return ""
+	}
+	attr := elem.SelectAttr(attributeName)
+	if attr == nil {
+		log.Debugf("Could not find attribute %s", attributeName)
+		return ""
+	}
+	return attr.Value
+}
+
+func XMLGetNodeValue(xmlString string, path string) string {
+	if _, ok := pathCache[path]; !ok {
+		compiledPath, err := etree.CompilePath(path)
+		if err != nil {
+			log.Errorf("Could not compile path %s: %s", path, err)
+			return ""
+		}
+		pathCache[path] = compiledPath
+	}
+
+	compiledPath := pathCache[path]
+	doc := etree.NewDocument()
+	err := doc.ReadFromString(xmlString)
+	if err != nil {
+		log.Tracef("Could not parse XML: %s", err)
+		return ""
+	}
+	elem := doc.FindElementPath(compiledPath)
+	if elem == nil {
+		log.Debugf("Could not find element %s", path)
+		return ""
+	}
+	return elem.Text()
+}

+ 115 - 0
pkg/exprhelpers/xml_test.go

@@ -0,0 +1,115 @@
+package exprhelpers
+
+import (
+	"log"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestXMLGetAttributeValue(t *testing.T) {
+	if err := Init(); err != nil {
+		log.Fatalf(err.Error())
+	}
+
+	tests := []struct {
+		name         string
+		xmlString    string
+		path         string
+		attribute    string
+		expectResult string
+	}{
+		{
+			name:         "XMLGetAttributeValue",
+			xmlString:    `<root><child attr="value"/></root>`,
+			path:         "/root/child",
+			attribute:    "attr",
+			expectResult: "value",
+		},
+		{
+			name:         "Non existing attribute for XMLGetAttributeValue",
+			xmlString:    `<root><child attr="value"/></root>`,
+			path:         "/root/child",
+			attribute:    "asdasd",
+			expectResult: "",
+		},
+		{
+			name:         "Non existing path for XMLGetAttributeValue",
+			xmlString:    `<root><child attr="value"/></root>`,
+			path:         "/foo/bar",
+			attribute:    "asdasd",
+			expectResult: "",
+		},
+		{
+			name:         "Invalid XML for XMLGetAttributeValue",
+			xmlString:    `<root><`,
+			path:         "/foo/bar",
+			attribute:    "asdasd",
+			expectResult: "",
+		},
+		{
+			name:         "Invalid path for XMLGetAttributeValue",
+			xmlString:    `<root><child attr="value"/></root>`,
+			path:         "/foo/bar[@",
+			attribute:    "asdasd",
+			expectResult: "",
+		},
+	}
+
+	for _, test := range tests {
+		result := XMLGetAttributeValue(test.xmlString, test.path, test.attribute)
+		isOk := assert.Equal(t, test.expectResult, result)
+		if !isOk {
+			t.Fatalf("test '%s' failed", test.name)
+		}
+		log.Printf("test '%s' : OK", test.name)
+	}
+
+}
+func TestXMLGetNodeValue(t *testing.T) {
+	if err := Init(); err != nil {
+		log.Fatalf(err.Error())
+	}
+
+	tests := []struct {
+		name         string
+		xmlString    string
+		path         string
+		expectResult string
+	}{
+		{
+			name:         "XMLGetNodeValue",
+			xmlString:    `<root><child>foobar</child></root>`,
+			path:         "/root/child",
+			expectResult: "foobar",
+		},
+		{
+			name:         "Non existing path for XMLGetNodeValue",
+			xmlString:    `<root><child>foobar</child></root>`,
+			path:         "/foo/bar",
+			expectResult: "",
+		},
+		{
+			name:         "Invalid XML for XMLGetNodeValue",
+			xmlString:    `<root><`,
+			path:         "/foo/bar",
+			expectResult: "",
+		},
+		{
+			name:         "Invalid path for XMLGetNodeValue",
+			xmlString:    `<root><child>foobar</child></root>`,
+			path:         "/foo/bar[@",
+			expectResult: "",
+		},
+	}
+
+	for _, test := range tests {
+		result := XMLGetNodeValue(test.xmlString, test.path)
+		isOk := assert.Equal(t, test.expectResult, result)
+		if !isOk {
+			t.Fatalf("test '%s' failed", test.name)
+		}
+		log.Printf("test '%s' : OK", test.name)
+	}
+
+}