@@ -72,21 +72,84 @@ type ValueMaskRule struct {
7272}
7373
7474func defaultValueMaskRule () * ValueMaskRule {
75- pat := `(?i)(\b(?:secret|password|passwd|pass|pw|token|api[_\-]?key|access[_\-]?key|private[_\-]?key)\b)( \s*)([=:\-])( \s*)(['"]?)([^\s'"]+) (['"]?)`
75+ pat := `(?i)(\b[A-Za-z0-9_\-\$]* (?:secret|password|passwd|pass|pw|token|api[_\-]?key|access[_\-]?key|private[_\-]?key)\b)\s*(:=|==|\|\||&&|=|:|\-) \s*(['"]?)`
7676 return & ValueMaskRule {
7777 KeyPattern : regexp .MustCompile (pat ),
7878 }
7979}
8080
8181func (r * ValueMaskRule ) MaskLine (line string ) string {
82- return r .KeyPattern .ReplaceAllStringFunc (line , func (s string ) string {
83- sub := r .KeyPattern .FindStringSubmatch (s )
84- if len (sub ) >= 8 {
85- // [1]=key, [2]=space_before, [3]=delim, [4]=space_after, [5]=quote, [6]=value, [7]=quote
86- return fmt .Sprintf ("%s%s%s%s%s*****MASKED*****%s" , sub [1 ], sub [2 ], sub [3 ], sub [4 ], sub [5 ], sub [7 ])
82+ result := ""
83+ rest := line
84+ for {
85+ m := r .KeyPattern .FindStringSubmatchIndex (rest )
86+ if m == nil {
87+ result += rest
88+ break
8789 }
88- return s
89- })
90+ // m[0] = full match start, m[1] = full match end,
91+ // m[2]=key start, m[3]=key end, m[4]=delimiter start,
92+ // m[5]=delimiter end, m[6]=quote start, m[7]=quote end
93+
94+ // 1. llways output the part after the previous match up to the key (commas, spaces, etc. can be entered here)
95+ result += rest [:m [2 ]]
96+
97+ // 2. print key, separator, leading space, and opening quote
98+ result += rest [m [2 ]:m [6 ]]
99+ quote := ""
100+ if m [6 ] != - 1 && m [7 ] != - 1 {
101+ quote = rest [m [6 ]:m [7 ]]
102+ result += quote
103+ }
104+
105+ maskedValue := "*****MASKED*****"
106+ valStart := m [7 ] // starting index of the value body (immediately after the quote)
107+ val := rest [valStart :]
108+
109+ if quote == `"` || quote == `'` {
110+ //With quotes: up to closing quote
111+ runes := []rune (val )
112+ escaped := false
113+ closingIdx := - 1
114+ for i := range len (runes ) {
115+ c := runes [i ]
116+ if escaped {
117+ escaped = false
118+ continue
119+ }
120+ if c == '\\' {
121+ escaped = true
122+ continue
123+ }
124+ if string (c ) == quote {
125+ closingIdx = i
126+ break
127+ }
128+ }
129+ result += maskedValue
130+ if closingIdx != - 1 {
131+ result += quote
132+ valStart += len (string (runes [:closingIdx + 1 ]))
133+ } else {
134+ valStart += len (val )
135+ }
136+ } else {
137+ // no quoted
138+ end := len (val )
139+ for i , c := range val {
140+ if c == ',' || c == ';' || c == ' ' {
141+ end = i
142+ break
143+ }
144+ }
145+ result += maskedValue
146+ valStart += end
147+ }
148+
149+ // remainder is rest.
150+ rest = rest [valStart :]
151+ }
152+ return result
90153}
91154
92155type RuleSet struct {
@@ -131,7 +194,7 @@ func (r *RuleSet) AddValueMaskKey(keywordList []string) {
131194 }
132195 keyword := strings .Join (quoted , "|" )
133196 // e.g. (?i)(secret|password|api_key)\s*([=:\-])\s*(['"]?)([^\s'"]+)(['"]?)
134- pat := fmt .Sprintf (`(?i)(%s)\s*([=:\-])\s*(['"]?)([^\s '"]+)(['"]?)` , keyword )
197+ pat := fmt .Sprintf (`(?i)(%s)\s*([=:\-])\s*(['"]?)([^'"]+)(['"]?)` , keyword )
135198 r .ValueMaskRules = append (r .ValueMaskRules , & ValueMaskRule {
136199 KeyPattern : regexp .MustCompile (pat ),
137200 })
0 commit comments