Files
gochat/backend/internal/webhookutil/sanitize.go
T
Rogeeandrogee 18ecee3e46 H-116: close visitor payload trust boundaries (#19)
* H-116: close visitor payload trust boundaries

* H-129: unblock SQLite backend tests

* H-129: remove stale last-seen response assertions

---------

Co-authored-by: Rogee <rogee@ipao.vip>
2026-08-15 01:15:04 +08:00

67 lines
1.6 KiB
Go

package webhookutil
import (
"encoding/json"
"strings"
)
var privateOutboundFields = map[string]struct{}{
"assignee": {},
"assignee_agent_bot_id": {},
"agent_bot_id": {},
"agent_name": {},
"assistant_id": {},
"assistant_name": {},
"bot_type": {},
"captain_assistant_id": {},
"performer": {},
"swt_baidu_agent_name": {},
"swt_baidu_conversation_type": {},
}
// SanitizeOutbound removes internal sender and AI identity from an external payload.
func SanitizeOutbound(value any) any {
raw, err := json.Marshal(value)
if err != nil {
return map[string]any{}
}
return SanitizeOutboundJSON(raw)
}
// SanitizeOutboundJSON decodes and sanitizes an external JSON object or array.
func SanitizeOutboundJSON(raw []byte) any {
var value any
if len(raw) == 0 || json.Unmarshal(raw, &value) != nil {
return map[string]any{}
}
switch value.(type) {
case map[string]any, []any:
return sanitizeOutboundValue(value)
default:
return map[string]any{}
}
}
func sanitizeOutboundValue(value any) any {
switch value := value.(type) {
case map[string]any:
clean := make(map[string]any, len(value))
for key, nested := range value {
_, private := privateOutboundFields[key]
if private || strings.HasPrefix(key, "sender") || strings.HasPrefix(key, "ai_takeover_") {
continue
}
clean[key] = sanitizeOutboundValue(nested)
}
return clean
case []any:
clean := make([]any, len(value))
for i, nested := range value {
clean[i] = sanitizeOutboundValue(nested)
}
return clean
default:
return value
}
}