package tgapi import ( "encoding/json" "errors" "fmt" "net/url" "strings" ) const redactedLogValue = "" 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("", len(data)) } redactLogValue(value) redacted, err := json.Marshal(value) if err != nil { return fmt.Sprintf("", 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 }