-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathjson_redacter.go
115 lines (102 loc) · 2.65 KB
/
json_redacter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package lager
import (
"encoding/json"
"regexp"
)
const awsAccessKeyIDPattern = `AKIA[A-Z0-9]{16}`
const awsSecretAccessKeyPattern = `KEY["']?\s*(?::|=>|=)\s*["']?[A-Z0-9/\+=]{40}["']?`
const cryptMD5Pattern = `\$1\$[A-Z0-9./]{1,16}\$[A-Z0-9./]{22}`
const cryptSHA256Pattern = `\$5\$[A-Z0-9./]{1,16}\$[A-Z0-9./]{43}`
const cryptSHA512Pattern = `\$6\$[A-Z0-9./]{1,16}\$[A-Z0-9./]{86}`
const privateKeyHeaderPattern = `-----BEGIN(.*)PRIVATE KEY-----`
type JSONRedacter struct {
keyMatchers []*regexp.Regexp
valueMatchers []*regexp.Regexp
}
func NewJSONRedacter(keyPatterns []string, valuePatterns []string) (*JSONRedacter, error) {
if keyPatterns == nil {
keyPatterns = []string{"[Pp]wd", "[Pp]ass"}
}
if valuePatterns == nil {
valuePatterns = DefaultValuePatterns()
}
ret := &JSONRedacter{}
for _, v := range keyPatterns {
r, err := regexp.Compile(v)
if err != nil {
return nil, err
}
ret.keyMatchers = append(ret.keyMatchers, r)
}
for _, v := range valuePatterns {
r, err := regexp.Compile(v)
if err != nil {
return nil, err
}
ret.valueMatchers = append(ret.valueMatchers, r)
}
return ret, nil
}
func (r JSONRedacter) Redact(data []byte) []byte {
var jsonBlob interface{}
err := json.Unmarshal(data, &jsonBlob)
if err != nil {
return handleError(err)
}
r.redactValue(&jsonBlob)
data, err = json.Marshal(jsonBlob)
if err != nil {
return handleError(err)
}
return data
}
func (r JSONRedacter) redactValue(data *interface{}) interface{} {
if data == nil {
return data
}
if a, ok := (*data).([]interface{}); ok {
r.redactArray(&a)
} else if m, ok := (*data).(map[string]interface{}); ok {
r.redactObject(&m)
} else if s, ok := (*data).(string); ok {
for _, m := range r.valueMatchers {
if m.MatchString(s) {
(*data) = "*REDACTED*"
break
}
}
}
return (*data)
}
func (r JSONRedacter) redactArray(data *[]interface{}) {
for i := range *data {
r.redactValue(&((*data)[i]))
}
}
func (r JSONRedacter) redactObject(data *map[string]interface{}) {
for k, v := range *data {
for _, m := range r.keyMatchers {
if m.MatchString(k) {
(*data)[k] = "*REDACTED*"
break
}
}
if (*data)[k] != "*REDACTED*" {
(*data)[k] = r.redactValue(&v)
}
}
}
func handleError(err error) []byte {
var content []byte
if _, ok := err.(*json.UnsupportedTypeError); ok {
data := map[string]interface{}{"lager serialisation error": err.Error()}
content, err = json.Marshal(data)
}
if err != nil {
panic(err)
}
return content
}
func DefaultValuePatterns() []string {
return []string{awsAccessKeyIDPattern, awsSecretAccessKeyPattern, cryptMD5Pattern, cryptSHA256Pattern, cryptSHA512Pattern, privateKeyHeaderPattern}
}