forked from baron/baron-sso
143 lines
3.9 KiB
Go
143 lines
3.9 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 parseBoolFlag(raw string) bool {
|
|
switch strings.ToLower(strings.TrimSpace(raw)) {
|
|
case "1", "true", "yes", "y", "on":
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func ClientDebugEnabled(appEnv, productionDebugFlag string) bool {
|
|
if !IsProductionEnv(appEnv) {
|
|
return true
|
|
}
|
|
return parseBoolFlag(productionDebugFlag)
|
|
}
|
|
|
|
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]interface{}) map[string]interface{} {
|
|
if len(data) == 0 {
|
|
return data
|
|
}
|
|
out := make(map[string]interface{}, len(data))
|
|
for k, v := range data {
|
|
if isSensitiveClientLogKey(k) {
|
|
out[k] = "*****"
|
|
continue
|
|
}
|
|
out[k] = sanitizeClientLogValue(v)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func sanitizeClientLogValue(v interface{}) interface{} {
|
|
switch val := v.(type) {
|
|
case map[string]interface{}:
|
|
return SanitizeClientLogData(val)
|
|
case []interface{}:
|
|
next := make([]interface{}, 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
|
|
}
|