FILE / ScuroNeko/Laniakea
tgapi/log_redaction.go
Исходный файл и его история в репозитории.
(fix): harden concurrent lifecycle (tests): add regression coverage (doc): update v1.2 guidance
87 lines
1.9 KiB
Go
87 lines
1.9 KiB
Go
package tgapi
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
const redactedLogValue = "<REDACTED>"
|
|
|
|
var sensitiveLogFields = map[string]struct{}{
|
|
"callback_data": {},
|
|
"credentials": {},
|
|
"data": {},
|
|
"invoice_payload": {},
|
|
"payload": {},
|
|
"provider_data": {},
|
|
"provider_token": {},
|
|
"secret": {},
|
|
"secret_token": {},
|
|
"token": {},
|
|
"web_app_query_id": {},
|
|
}
|
|
|
|
func redactRequestLog(data []byte) string {
|
|
var value any
|
|
if err := json.Unmarshal(data, &value); err != nil {
|
|
return fmt.Sprintf("<invalid JSON omitted: %d bytes>", len(data))
|
|
}
|
|
redactLogValue(value)
|
|
redacted, err := json.Marshal(value)
|
|
if err != nil {
|
|
return fmt.Sprintf("<unavailable JSON omitted: %d bytes>", len(data))
|
|
}
|
|
return string(redacted)
|
|
}
|
|
|
|
func redactLogValue(value any) {
|
|
switch value := value.(type) {
|
|
case map[string]any:
|
|
for key, item := range value {
|
|
if _, sensitive := sensitiveLogFields[strings.ToLower(key)]; sensitive {
|
|
value[key] = redactedLogValue
|
|
continue
|
|
}
|
|
redactLogValue(item)
|
|
}
|
|
case []any:
|
|
for _, item := range value {
|
|
redactLogValue(item)
|
|
}
|
|
}
|
|
}
|
|
|
|
func responseLogSummary(method string, size int) string {
|
|
return fmt.Sprintf("method=%s bytes=%d body=omitted", method, size)
|
|
}
|
|
|
|
type redactedError struct {
|
|
err error
|
|
secret string
|
|
}
|
|
|
|
func (e *redactedError) Error() string {
|
|
return strings.ReplaceAll(e.err.Error(), e.secret, redactedLogValue)
|
|
}
|
|
|
|
func (e *redactedError) Unwrap() error { return e.err }
|
|
|
|
func redactHTTPError(err error, token string) error {
|
|
if err == nil || token == "" || !strings.Contains(err.Error(), token) {
|
|
return err
|
|
}
|
|
|
|
var urlErr *url.Error
|
|
if !errors.As(err, &urlErr) {
|
|
return &redactedError{err: err, secret: token}
|
|
}
|
|
|
|
redactedURL := *urlErr
|
|
redactedURL.URL = strings.ReplaceAll(redactedURL.URL, token, redactedLogValue)
|
|
redactedURL.Err = &redactedError{err: urlErr.Err, secret: token}
|
|
return &redactedURL
|
|
}
|