feat: block WhatsApp group messages with GroupTrigger support

Add GroupTrigger field to WhatsAppConfig (was missing — other channels
like Telegram already had it). When mention_only is true, group messages
are silently dropped before reaching the LLM.

Prevents magic links and subscriber data from leaking in group chats.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Diego Fornalha 2026-04-04 04:09:06 -03:00
parent 84e42d6904
commit 35b96786f6
2 changed files with 13 additions and 2 deletions

View file

@ -364,6 +364,12 @@ func (c *WhatsAppNativeChannel) handleIncoming(evt *events.Message) {
metadata["user_name"] = evt.Info.PushName
}
if evt.Info.Chat.Server == types.GroupServer {
// Skip group messages when mention_only is enabled — prevents
// data leaks (magic links, subscriber info) in public groups.
if c.cfg.GroupTrigger.MentionOnly {
logger.DebugCF("whatsapp", "ignoring group message (mention_only)", map[string]any{"chat": chatID})
return
}
metadata["peer_kind"] = "group"
metadata["peer_id"] = chatID
} else {

View file

@ -340,6 +340,7 @@ type WhatsAppConfig struct {
UseNative bool `json:"use_native" yaml:"-" env:"PICOCLAW_CHANNELS_WHATSAPP_USE_NATIVE"`
SessionStorePath string `json:"session_store_path" yaml:"-" env:"PICOCLAW_CHANNELS_WHATSAPP_SESSION_STORE_PATH"`
AllowFrom FlexibleStringSlice `json:"allow_from" yaml:"-" env:"PICOCLAW_CHANNELS_WHATSAPP_ALLOW_FROM"`
GroupTrigger GroupTriggerConfig `json:"group_trigger,omitempty" yaml:"-"`
ReasoningChannelID string `json:"reasoning_channel_id" yaml:"-" env:"PICOCLAW_CHANNELS_WHATSAPP_REASONING_CHANNEL_ID"`
}
@ -1027,7 +1028,9 @@ func LoadConfig(path string) (*Config, error) {
return nil, fmt.Errorf("failed to load existing security config: %w", secErr)
}
defer func(cfg *Config) {
_ = SaveConfig(path, cfg)
if saveErr := SaveConfig(path, cfg); saveErr != nil {
logger.ErrorF("failed to save config after v0 migration", map[string]any{"error": saveErr})
}
}(cfg)
case 1:
// V1→V2 migration: infer Enabled and migrate channel config fields
@ -1061,7 +1064,9 @@ func LoadConfig(path string) (*Config, error) {
}
defer func(cfg *Config) {
_ = SaveConfig(path, cfg)
if saveErr := SaveConfig(path, cfg); saveErr != nil {
logger.ErrorF("failed to save config after v1 migration", map[string]any{"error": saveErr})
}
}(cfg)
logger.InfoF(
"config migrate success",