Files
Local-Cursor/internal/logger/redact.go
FuDie0915 188225fae6 Ð޸´ȫÏîĿÉó²éÎÊÌⲢ·¢²¼ v1.1.9
¸ÄÓñ¾»ú¶ÀÁ¢ CA£¬»ָ´ CLI TLS УÑ飬±£»¤ƾ¾ÝÓëÅäÖò¢·¢±£´档
Ð޸´ Cursor Êý¾ݡ¢»Ự·¾¶¡¢´úÀíÉúÃüÖÜÆڡ¢ģÐÍÇëÇóÓë Skills Îļþ²Ù×÷¡£
Ϊ¶ÀÁ¢ Tab ·þÎñÔö¼ӿͻ§¶˼øȨ£¬Éý¼¶ÒÀÀµÓ빤¾ßÁ´£¬ÍêÉƷ¢²¼ԪÐÅϢͬ²½¡£

Ñé֤£ºÁ½¸ö Go ģ¿éµIJâÊÔ/vet¡¢¹ؼüģ¿é race¡¢ǰ¶˲âÊÔ/Éú²ú¹¹½¨/Éó¼ơ¢
Go ¿ɴï©¶´ɨÃèÓë macOS/Linux ¿ÉÐÐģ¿齻²æ±àÒë¾ùͨ¹ý¡£
Windows ¸ôÀëÆô¶¯ͨ¹ý£»δÍê³ɵĵã»÷ðÑ̺ÍԭÉúƽ̨Ñé֤¼ûÉó²鱨¸档
2026-11-10 09:59:34 +08:00

86 lines
2.5 KiB
Go

package logger
import (
"context"
"fmt"
"log/slog"
"regexp"
"sort"
"strings"
"sync"
)
var secretRegistry = struct {
sync.RWMutex
values map[string]struct{}
}{values: map[string]struct{}{}}
var bearerPattern = regexp.MustCompile(`(?i)Bearer\s+[^\s"'<>]+`)
var credentialPattern = regexp.MustCompile(`(?i)((?:api[_-]?key|token|authorization|cookie|password|secret)["']?\s*[:=]\s*["']?)[^"'\s,;}]+`)
func RegisterSecrets(values ...string) {
secretRegistry.Lock()
defer secretRegistry.Unlock()
for _, v := range values {
if v != "" {
secretRegistry.values[v] = struct{}{}
}
}
}
func redact(s string) string {
secretRegistry.RLock()
values := make([]string, 0, len(secretRegistry.values))
for value := range secretRegistry.values {
values = append(values, value)
}
secretRegistry.RUnlock()
sort.Slice(values, func(i, j int) bool { return len(values[i]) > len(values[j]) })
for _, value := range values {
s = strings.ReplaceAll(s, value, "[redacted]")
}
s = bearerPattern.ReplaceAllString(s, "Bearer [redacted]")
return credentialPattern.ReplaceAllString(s, "${1}[redacted]")
}
type redactingHandler struct{ next slog.Handler }
func (h redactingHandler) Enabled(ctx context.Context, level slog.Level) bool {
return h.next.Enabled(ctx, level)
}
func redactAttr(a slog.Attr) slog.Attr {
key := strings.ToLower(a.Key)
for _, part := range []string{"apikey", "api_key", "token", "password", "secret", "authorization", "cookie", "payload", "headers", "body", "config"} {
if strings.Contains(key, part) {
return slog.String(a.Key, "[redacted]")
}
}
v := a.Value.Resolve()
switch v.Kind() {
case slog.KindString:
a.Value = slog.StringValue(redact(v.String()))
case slog.KindAny:
a.Value = slog.StringValue(redact(fmt.Sprint(v.Any())))
case slog.KindGroup:
attrs := v.Group()
for i := range attrs {
attrs[i] = redactAttr(attrs[i])
}
a.Value = slog.GroupValue(attrs...)
}
return a
}
func (h redactingHandler) Handle(ctx context.Context, r slog.Record) error {
next := slog.NewRecord(r.Time, r.Level, redact(r.Message), r.PC)
r.Attrs(func(a slog.Attr) bool { next.AddAttrs(redactAttr(a)); return true })
return h.next.Handle(ctx, next)
}
func (h redactingHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
copy := append([]slog.Attr(nil), attrs...)
for i := range copy {
copy[i] = redactAttr(copy[i])
}
return redactingHandler{h.next.WithAttrs(copy)}
}
func (h redactingHandler) WithGroup(name string) slog.Handler {
return redactingHandler{h.next.WithGroup(name)}
}