owpengram-server/internal/rpc/channel_fanout_privacy_bot_rpc_test.go
2026-09-01 12:06:31 +03:00

84 lines
3.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package rpc
import (
"context"
"testing"
"github.com/iamxvbaba/td/clock"
"go.uber.org/zap/zaptest"
appchannels "telesrv/internal/app/channels"
"telesrv/internal/domain"
"telesrv/internal/store/memory"
)
// privacyBotResolver 让指定 user 成为 bot_chat_history=false 的隐私 bot命令/@/回复以外的群消息不可见)。
type privacyBotResolver map[int64]bool
func (p privacyBotResolver) BotInfo(_ context.Context, botUserID int64) (domain.BotProfile, bool, error) {
if _, ok := p[botUserID]; !ok {
return domain.BotProfile{}, false, nil
}
return domain.BotProfile{BotUserID: botUserID, ChatHistory: false}, true, nil
}
// TestChannelMessageFanoutSkipsPrivacyBotOnlinePush 回归:在线 privacy bot 不得经实时 fanout 收到群里
// 的纯文本消息。修复前 channelFanoutRecipients 按「在线活跃成员」重算 recipients,会把 send 时已按
// SkipDeliveryUserIDs 排除的 bot 加回 → 在线 bot 实时收到全部群聊内容(持久 history/difference 已正确
// 隐藏,仅此直接推送泄漏内容)。修复后 fanout build 对被 skip 的 viewer 返回 nil,不推送。
func TestChannelMessageFanoutSkipsPrivacyBotOnlinePush(t *testing.T) {
ctx := context.Background()
channelStore := memory.NewChannelStore()
bots := privacyBotResolver{1003: true}
channelService := appchannels.NewService(channelStore, appchannels.WithBotProfileResolver(bots))
created, err := channelService.CreateMegagroupFromCreateChat(ctx, 1001, domain.CreateChannelRequest{
Title: "Privacy",
MemberUserIDs: []int64{1002, 1003},
Date: 10,
})
if err != nil {
t.Fatalf("create channel: %v", err)
}
// 纯文本消息:privacy bot 1003 不可见 → SendMessage 把它放进 SkipDeliveryUserIDs、排除出 Recipients。
res, err := channelService.SendMessage(ctx, 1001, domain.SendChannelMessageRequest{
ChannelID: created.Channel.ID,
RandomID: 2001,
Message: "plain group chatter",
Date: 11,
})
if err != nil {
t.Fatalf("send: %v", err)
}
if !fanoutHasID(res.SkipDeliveryUserIDs, 1003) {
t.Fatalf("res.SkipDeliveryUserIDs = %v, want privacy bot 1003 excluded at send", res.SkipDeliveryUserIDs)
}
if fanoutHasID(res.Recipients, 1003) {
t.Fatalf("res.Recipients = %v, privacy bot 1003 must not be a delivery recipient", res.Recipients)
}
// 两成员都在线;channelFanoutRecipients 据此把 1003 当在线活跃成员加回 recipients。
sessions := &captureSessions{
channelMembers: map[int64][]int64{created.Channel.ID: {1002, 1003}},
}
users := &prefetchRecordingUsersService{mapUsersService: mapUsersService{users: map[int64]domain.User{
1001: {ID: 1001, FirstName: "sender"},
}}}
r := New(Config{}, Deps{Channels: channelService, Sessions: sessions, Users: users}, zaptest.NewLogger(t), clock.System)
// 复核前置:修复前后 channelFanoutRecipients 都会把 1003 列进 recipients(在线活跃成员),
// 漏洞/修复的差异在 build 是否对它返回 nil。
got := r.channelFanoutRecipients(ctx, channelFanoutMembers, created.Channel.ID, res.Recipients)
if !fanoutHasID(got, 1003) {
t.Fatalf("channelFanoutRecipients = %v, 期望在线活跃成员 1003 仍被列入(否则测不到 build 跳过)", got)
}
r.enqueueChannelMessageFanout(ctx, 1001, res, nil)
pushed := sessions.pushedUserIDs()
if !fanoutHasID(pushed, 1002) {
t.Fatalf("fanout pushed = %v, want human member 1002 to receive online push", pushed)
}
if fanoutHasID(pushed, 1003) {
t.Fatalf("fanout pushed = %v, online privacy bot 1003 must NOT receive plain-message push (privacy leak)", pushed)
}
}