1
0
forked from baron/baron-sso
Files
baron-sso/backend/internal/logger/client_log_policy.go
chan 31d107ff2e feat(user): support fixed UUID registration and enhance bulk import results
- Added support for fixed UUIDs during bulk registration (Search-first + ExternalID mapping)
- Implemented idempotency and visibility restoration for soft-deleted users
- Enhanced bulk upload UI to show 'New/Updated/Unchanged' status and modified fields
- Added logic to reclaim identifiers (login_id) from colliding records
- Added frontend E2E and backend unit tests for UUID integrity and conflict handling
- Fixed i18n, formatting, and mock tests to satisfy code-check
- Applied 'go fix' for 'omitzero' tags and general Go standards
2026-06-01 15:34:08 +09:00

148 lines
4.0 KiB
Go

package logger
import (
"log/slog"
"regexp"
"strings"
)
var sensitiveClientLogKeys = map[string]struct{}{
"password": {},
"currentpassword": {},
"newpassword": {},
"oldpassword": {},
"token": {},
"accesstoken": {},
"refreshtoken": {},
"secret": {},
"clientsecret": {},
"authorization": {},
"cookie": {},
"setcookie": {},
"verificationcode": {},
"code": {},
"loginchallenge": {},
"loginverifier": {},
"sessionjwt": {},
"accessjwt": {},
"refreshjwt": {},
}
var (
logJSONSensitivePattern = regexp.MustCompile(`(?i)"(password|currentpassword|newpassword|oldpassword|token|accesstoken|refreshtoken|secret|clientsecret|authorization|cookie|setcookie|verificationcode|code|loginchallenge|loginverifier|sessionjwt|accessjwt|refreshjwt)"\s*:\s*"[^"]*"`)
logKVPattern = regexp.MustCompile(`(?i)\b(password|current_password|currentpassword|new_password|newpassword|old_password|oldpassword|token|access_token|accesstoken|refresh_token|refreshtoken|authorization|cookie|session_jwt|sessionjwt|access_jwt|accessjwt|refresh_jwt|refreshjwt)\b\s*[:=]\s*([^\s,;]+)`)
)
func IsProductionEnv(appEnv string) bool {
return IsProductionLikeEnv(appEnv)
}
func parseOptionalBoolFlag(raw string) (bool, bool) {
switch strings.ToLower(strings.TrimSpace(raw)) {
case "1", "true", "yes", "y", "on":
return true, true
case "0", "false", "no", "n", "off":
return false, true
default:
return false, false
}
}
func ClientDebugEnabled(appEnv, debugFlag string) bool {
if enabled, ok := parseOptionalBoolFlag(debugFlag); ok {
return enabled
}
if !IsProductionEnv(appEnv) {
return true
}
return false
}
func NormalizeClientLogLevel(level string) slog.Level {
switch strings.ToUpper(strings.TrimSpace(level)) {
case "SEVERE", "ERROR":
return slog.LevelError
case "WARNING", "WARN":
return slog.LevelWarn
case "DEBUG", "FINE", "TRACE":
return slog.LevelDebug
default:
return slog.LevelInfo
}
}
func ShouldAcceptClientLog(appEnv, productionDebugFlag, level string) bool {
if ClientDebugEnabled(appEnv, productionDebugFlag) {
return true
}
return NormalizeClientLogLevel(level) >= slog.LevelWarn
}
func ShouldFilterNoisyClientInfo(appEnv, productionDebugFlag, message string) bool {
if ClientDebugEnabled(appEnv, productionDebugFlag) {
return false
}
msg := strings.ToLower(message)
return strings.Contains(msg, "navigating to") ||
strings.Contains(msg, "going to") ||
strings.Contains(msg, "redirecting to") ||
strings.Contains(msg, "full paths for routes")
}
func SanitizeClientLogMessage(message string) string {
if strings.TrimSpace(message) == "" {
return message
}
sanitized := logJSONSensitivePattern.ReplaceAllStringFunc(message, func(segment string) string {
parts := strings.SplitN(segment, ":", 2)
if len(parts) != 2 {
return segment
}
return parts[0] + `:"*****"`
})
sanitized = logKVPattern.ReplaceAllString(sanitized, `$1=*****`)
return sanitized
}
func SanitizeClientLogData(data map[string]any) map[string]any {
if len(data) == 0 {
return data
}
out := make(map[string]any, len(data))
for k, v := range data {
if isSensitiveClientLogKey(k) {
out[k] = "*****"
continue
}
out[k] = sanitizeClientLogValue(v)
}
return out
}
func sanitizeClientLogValue(v any) any {
switch val := v.(type) {
case map[string]any:
return SanitizeClientLogData(val)
case []any:
next := make([]any, len(val))
for i := range val {
next[i] = sanitizeClientLogValue(val[i])
}
return next
case string:
return SanitizeClientLogMessage(val)
default:
return val
}
}
func isSensitiveClientLogKey(key string) bool {
normalized := strings.ToLower(strings.TrimSpace(key))
normalized = strings.ReplaceAll(normalized, "-", "")
normalized = strings.ReplaceAll(normalized, "_", "")
normalized = strings.ReplaceAll(normalized, ".", "")
normalized = strings.ReplaceAll(normalized, " ", "")
_, ok := sensitiveClientLogKeys[normalized]
return ok
}