Skip to content

Commit 9f45806

Browse files
committed
feat(logging): centralize sensitive header masking
1 parent 307ae76 commit 9f45806

File tree

3 files changed

+52
-17
lines changed

3 files changed

+52
-17
lines changed

internal/logging/request_logger.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"time"
1717

1818
"github.com/router-for-me/CLIProxyAPI/v6/internal/interfaces"
19+
"github.com/router-for-me/CLIProxyAPI/v6/internal/util"
1920
)
2021

2122
// RequestLogger defines the interface for logging HTTP requests and responses.
@@ -485,7 +486,8 @@ func (l *FileRequestLogger) formatRequestInfo(url, method string, headers map[st
485486
content.WriteString("=== HEADERS ===\n")
486487
for key, values := range headers {
487488
for _, value := range values {
488-
content.WriteString(fmt.Sprintf("%s: %s\n", key, value))
489+
masked := util.MaskSensitiveHeaderValue(key, value)
490+
content.WriteString(fmt.Sprintf("%s: %s\n", key, masked))
489491
}
490492
}
491493
content.WriteString("\n")

internal/runtime/executor/logging_helpers.go

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,8 @@ func writeHeaders(builder *strings.Builder, headers http.Header) {
275275
continue
276276
}
277277
for _, value := range values {
278-
builder.WriteString(fmt.Sprintf("%s: %s\n", key, sanitizeHeaderValue(key, value)))
278+
masked := util.MaskSensitiveHeaderValue(key, value)
279+
builder.WriteString(fmt.Sprintf("%s: %s\n", key, masked))
279280
}
280281
}
281282
}
@@ -319,18 +320,3 @@ func formatAuthInfo(info upstreamRequestLog) string {
319320

320321
return strings.Join(parts, ", ")
321322
}
322-
323-
func sanitizeHeaderValue(key, value string) string {
324-
trimmedValue := strings.TrimSpace(value)
325-
lowerKey := strings.ToLower(strings.TrimSpace(key))
326-
switch {
327-
case strings.Contains(lowerKey, "authorization"),
328-
strings.Contains(lowerKey, "api-key"),
329-
strings.Contains(lowerKey, "apikey"),
330-
strings.Contains(lowerKey, "token"),
331-
strings.Contains(lowerKey, "secret"):
332-
return util.HideAPIKey(trimmedValue)
333-
default:
334-
return trimmedValue
335-
}
336-
}

internal/util/provider.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
package util
55

66
import (
7+
"strings"
8+
79
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
810
"github.com/router-for-me/CLIProxyAPI/v6/internal/registry"
911
)
@@ -141,3 +143,48 @@ func HideAPIKey(apiKey string) string {
141143
}
142144
return apiKey
143145
}
146+
147+
// maskAuthorizationHeader masks the Authorization header value while preserving the auth type prefix.
148+
// Common formats: "Bearer <token>", "Basic <credentials>", "ApiKey <key>", etc.
149+
// It preserves the prefix (e.g., "Bearer ") and only masks the token/credential part.
150+
//
151+
// Parameters:
152+
// - value: The Authorization header value
153+
//
154+
// Returns:
155+
// - string: The masked Authorization value with prefix preserved
156+
func MaskAuthorizationHeader(value string) string {
157+
parts := strings.SplitN(strings.TrimSpace(value), " ", 2)
158+
if len(parts) < 2 {
159+
return HideAPIKey(value)
160+
}
161+
return parts[0] + " " + HideAPIKey(parts[1])
162+
}
163+
164+
// MaskSensitiveHeaderValue masks sensitive header values while preserving expected formats.
165+
//
166+
// Behavior by header key (case-insensitive):
167+
// - "Authorization": Preserve the auth type prefix (e.g., "Bearer ") and mask only the credential part.
168+
// - Headers containing "api-key": Mask the entire value using HideAPIKey.
169+
// - Others: Return the original value unchanged.
170+
//
171+
// Parameters:
172+
// - key: The HTTP header name to inspect (case-insensitive matching).
173+
// - value: The header value to mask when sensitive.
174+
//
175+
// Returns:
176+
// - string: The masked value according to the header type; unchanged if not sensitive.
177+
func MaskSensitiveHeaderValue(key, value string) string {
178+
lowerKey := strings.ToLower(strings.TrimSpace(key))
179+
switch {
180+
case lowerKey == "authorization":
181+
return MaskAuthorizationHeader(value)
182+
case strings.Contains(lowerKey, "api-key"),
183+
strings.Contains(lowerKey, "apikey"),
184+
strings.Contains(lowerKey, "token"),
185+
strings.Contains(lowerKey, "secret"):
186+
return HideAPIKey(value)
187+
default:
188+
return value
189+
}
190+
}

0 commit comments

Comments
 (0)