From 84113cff2f85afd627c51f6b4279451024adebf2 Mon Sep 17 00:00:00 2001 From: Duc Nguyen Date: Sat, 7 Mar 2026 07:12:47 +0700 Subject: [PATCH] fix(channels): fix Zalo personal group pairing bypass and reply thread type (#76) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two bugs in Zalo personal channel policy: 1. Group pairing bypass: checkGroupPolicy() called IsAllowed(groupID) directly, which returns true when allowlist is empty — effectively skipping pairing for all groups. Fixed to match the DM pairing pattern: HasAllowList() && IsAllowed(groupID). 2. Wrong thread type for group pairing reply: sendPairingReply() always used ThreadTypeUser even when replying to a group. Now detects group sender IDs (prefixed "group:") and uses ThreadTypeGroup. --- internal/channels/zalo/personal/policy.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/internal/channels/zalo/personal/policy.go b/internal/channels/zalo/personal/policy.go index a977be1f..9385986c 100644 --- a/internal/channels/zalo/personal/policy.go +++ b/internal/channels/zalo/personal/policy.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log/slog" + "strings" "time" "github.com/nextlevelbuilder/goclaw/internal/channels/zalo/personal/protocol" @@ -73,9 +74,14 @@ func (c *Channel) sendPairingReply(senderID, chatID string) { senderID, code, code, ) + threadType := protocol.ThreadTypeUser + if strings.HasPrefix(senderID, "group:") { + threadType = protocol.ThreadTypeGroup + } + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - if _, err := protocol.SendMessage(ctx, sess, chatID, protocol.ThreadTypeUser, replyText); err != nil { + if _, err := protocol.SendMessage(ctx, sess, chatID, threadType, replyText); err != nil { slog.Warn("zalo_personal: failed to send pairing reply", "error", err) } else { c.pairingDebounce.Store(senderID, time.Now()) @@ -102,7 +108,7 @@ func (c *Channel) checkGroupPolicy(senderID, groupID string, mentions []*protoco } case "pairing": - if c.IsAllowed(groupID) { + if c.HasAllowList() && c.IsAllowed(groupID) { // pass — allowlist bypass } else if _, cached := c.approvedGroups.Load(groupID); cached { // pass — already approved