package logredact import ( "encoding/json" "strings" ) // maxRedactDepth 限制递归深度以防止栈溢出 const maxRedactDepth = 32 var defaultSensitiveKeys = map[string]struct{}{ "authorization_code": {}, "code": {}, "code_verifier": {}, "access_token": {}, "refresh_token": {}, "id_token": {}, "client_secret": {}, "password": {}, } func RedactMap(input map[string]any, extraKeys ...string) map[string]any { if input == nil { return map[string]any{} } keys := buildKeySet(extraKeys) redacted, ok := redactValueWithDepth(input, keys, 0).(map[string]any) if !ok { return map[string]any{} } return redacted } func RedactJSON(raw []byte, extraKeys ...string) string { if len(raw) == 0 { return "" } var value any if err := json.Unmarshal(raw, &value); err != nil { return "" } keys := buildKeySet(extraKeys) redacted := redactValueWithDepth(value, keys, 0) encoded, err := json.Marshal(redacted) if err != nil { return "" } return string(encoded) } func buildKeySet(extraKeys []string) map[string]struct{} { keys := make(map[string]struct{}, len(defaultSensitiveKeys)+len(extraKeys)) for k := range defaultSensitiveKeys { keys[k] = struct{}{} } for _, key := range extraKeys { normalized := normalizeKey(key) if normalized == "" { continue } keys[normalized] = struct{}{} } return keys } func redactValueWithDepth(value any, keys map[string]struct{}, depth int) any { if depth > maxRedactDepth { return "" } switch v := value.(type) { case map[string]any: out := make(map[string]any, len(v)) for k, val := range v { if isSensitiveKey(k, keys) { out[k] = "***" continue } out[k] = redactValueWithDepth(val, keys, depth+1) } return out case []any: out := make([]any, len(v)) for i, item := range v { out[i] = redactValueWithDepth(item, keys, depth+1) } return out default: return value } } func isSensitiveKey(key string, keys map[string]struct{}) bool { _, ok := keys[normalizeKey(key)] return ok } func normalizeKey(key string) string { return strings.ToLower(strings.TrimSpace(key)) }