forked from samber/slog-multi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgdpr.go
99 lines (81 loc) · 1.95 KB
/
gdpr.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
package main
import (
"context"
"strings"
"log/slog"
"github.com/samber/lo"
slogmulti "github.com/samber/slog-multi"
)
func NewGDPRMiddleware() slogmulti.Middleware {
return func(next slog.Handler) slog.Handler {
return &gdprMiddleware{
next: next,
anonymize: false,
}
}
}
type gdprMiddleware struct {
next slog.Handler
anonymize bool
}
func (h *gdprMiddleware) Enabled(ctx context.Context, level slog.Level) bool {
return h.next.Enabled(ctx, level)
}
func (h *gdprMiddleware) Handle(ctx context.Context, record slog.Record) error {
attrs := []slog.Attr{}
record.Attrs(func(attr slog.Attr) bool {
if mightContainPII(attr.Key) {
attrs = append(attrs, anonymize(attr))
} else {
attrs = append(attrs, attr)
}
return true
})
// new record with anonymized data
record = slog.NewRecord(record.Time, record.Level, record.Message, record.PC)
record.AddAttrs(attrs...)
return h.next.Handle(ctx, record)
}
func (h *gdprMiddleware) WithAttrs(attrs []slog.Attr) slog.Handler {
if h.anonymize {
for i := range attrs {
attrs[i] = anonymize(attrs[i])
}
}
for i := range attrs {
if mightContainPII(attrs[i].Key) {
attrs[i] = anonymize(attrs[i])
}
}
return &gdprMiddleware{
next: h.next.WithAttrs(attrs),
anonymize: h.anonymize,
}
}
func (h *gdprMiddleware) WithGroup(name string) slog.Handler {
return &gdprMiddleware{
next: h.next.WithGroup(name),
anonymize: h.anonymize || mightContainPII(name),
}
}
func mightContainPII(key string) bool {
return key == "user" ||
strings.Index(key, "user_") == 0 ||
strings.Index(key, "user-") == 0 ||
strings.Index(key, "user.") == 0
}
func anonymize(attr slog.Attr) slog.Attr {
k := attr.Key
v := attr.Value
kind := attr.Value.Kind()
switch kind {
case slog.KindGroup:
attrs := v.Group()
for i := range attrs {
attrs[i] = anonymize(attrs[i])
}
return slog.Group(k, lo.ToAnySlice(attrs)...)
default:
return slog.String(k, "*******")
}
}