github.com/DataDog/datadog-agent/pkg/security/secl@v0.55.0-devel.0.20240517055856-10c4965fea94/compiler/eval/pattern.go (about) 1 // Unless explicitly stated otherwise all files in this repository are licensed 2 // under the Apache License Version 2.0. 3 // This product includes software developed at Datadog (https://www.datadoghq.com/). 4 // Copyright 2016-present Datadog, Inc. 5 6 // Package eval holds eval related files 7 package eval 8 9 import ( 10 "strings" 11 ) 12 13 func nextSegment(str string) (bool, string, int) { 14 var inSegment bool 15 var start, end int 16 17 var star bool 18 if str[0] == '*' { 19 star = true 20 } 21 22 for i, c := range []byte(str) { 23 if c != '*' { 24 if !inSegment { 25 start = i 26 inSegment = true 27 } 28 end = i 29 } else if inSegment { 30 break 31 } 32 } 33 34 if star && start == 0 { 35 return star, "", 1 36 } 37 38 end++ 39 40 return star, str[start:end], end 41 } 42 43 func index(s, subtr string, caseInsensitive bool) int { 44 if caseInsensitive { 45 s = strings.ToLower(s) 46 subtr = strings.ToLower(subtr) 47 } 48 return strings.Index(s, subtr) 49 } 50 51 func hasPrefix(s, prefix string, caseInsensitive bool) bool { 52 if caseInsensitive { 53 s = strings.ToLower(s) 54 prefix = strings.ToLower(prefix) 55 } 56 return strings.HasPrefix(s, prefix) 57 } 58 59 // PatternMatches matches a pattern against a string 60 func PatternMatches(pattern string, str string, caseInsensitive bool) bool { 61 patternElem := newPatternElement(pattern) 62 return PatternMatchesWithSegments(patternElem, str, caseInsensitive) 63 } 64 65 // PatternMatchesWithSegments matches a pattern against a string 66 func PatternMatchesWithSegments(patternElem patternElement, str string, caseInsensitive bool) bool { 67 if patternElem.pattern == "*" { 68 return true 69 } 70 71 if len(patternElem.pattern) == 0 { 72 return len(str) == 0 73 } 74 75 for _, seg := range patternElem.segments { 76 if seg.star { 77 // there is no pattern to match after the last star 78 if len(seg.segment) == 0 { 79 return true 80 } 81 82 index := index(str, seg.segment, caseInsensitive) 83 if index == -1 { 84 return false 85 } 86 str = str[index+len(seg.segment):] 87 } else { 88 if !hasPrefix(str, seg.segment, caseInsensitive) { 89 return false 90 } 91 str = str[len(seg.segment):] 92 } 93 } 94 95 // return false if there is still some str to match 96 return len(str) == 0 97 } 98 99 type patternElement struct { 100 pattern string 101 segments []patternSegment 102 } 103 104 type patternSegment struct { 105 star bool 106 segment string 107 } 108 109 func newPatternElement(element string) patternElement { 110 el := patternElement{ 111 pattern: element, 112 } 113 114 for len(element) > 0 { 115 star, segment, nextIndex := nextSegment(element) 116 element = element[nextIndex:] 117 el.segments = append(el.segments, patternSegment{star, segment}) 118 } 119 120 return el 121 }