Browse Source

fix(tgbot): ignore commands for other bots (#4894)

Telegram group chats can contain multiple bots. Commands addressed to another bot, such as /status@other_bot, should not be handled by the 3x-ui bot.

Closes #4893
康厚超 20 hours ago
parent
commit
73ce11508e
2 changed files with 44 additions and 0 deletions
  1. 20 0
      web/service/tgbot.go
  2. 24 0
      web/service/tgbot_test.go

+ 20 - 0
web/service/tgbot.go

@@ -495,6 +495,10 @@ func (t *Tgbot) OnReceive() {
 		}, th.TextEqual(t.I18nBot("tgbot.buttons.closeKeyboard")))
 		}, th.TextEqual(t.I18nBot("tgbot.buttons.closeKeyboard")))
 
 
 		h.HandleMessage(func(ctx *th.Context, message telego.Message) error {
 		h.HandleMessage(func(ctx *th.Context, message telego.Message) error {
+			if !t.isCommandForCurrentBot(&message) {
+				return nil
+			}
+
 			// Use goroutine with worker pool for concurrent command processing
 			// Use goroutine with worker pool for concurrent command processing
 			go func() {
 			go func() {
 				messageWorkerPool <- struct{}{}        // Acquire worker
 				messageWorkerPool <- struct{}{}        // Acquire worker
@@ -684,6 +688,22 @@ func (t *Tgbot) answerCommand(message *telego.Message, chatId int64, isAdmin boo
 	}
 	}
 }
 }
 
 
+func (t *Tgbot) isCommandForCurrentBot(message *telego.Message) bool {
+	return isCommandForBot(message.Text, botUsername())
+}
+
+func botUsername() string {
+	if bot == nil {
+		return ""
+	}
+	return bot.Username()
+}
+
+func isCommandForBot(text string, username string) bool {
+	_, commandUsername, _ := tu.ParseCommand(text)
+	return commandUsername == "" || username == "" || strings.EqualFold(commandUsername, username)
+}
+
 // sendResponse sends the response message based on the onlyMessage flag.
 // sendResponse sends the response message based on the onlyMessage flag.
 func (t *Tgbot) sendResponse(chatId int64, msg string, onlyMessage, isAdmin bool) {
 func (t *Tgbot) sendResponse(chatId int64, msg string, onlyMessage, isAdmin bool) {
 	if onlyMessage {
 	if onlyMessage {

+ 24 - 0
web/service/tgbot_test.go

@@ -99,3 +99,27 @@ func TestTgbotProxyDialerNoneWhenEmpty(t *testing.T) {
 		t.Fatal("Dial must be nil when no proxy is configured")
 		t.Fatal("Dial must be nil when no proxy is configured")
 	}
 	}
 }
 }
+
+func TestIsCommandForBotAllowsUntargetedCommand(t *testing.T) {
+	if !isCommandForBot("/status", "panel_bot") {
+		t.Fatal("untargeted commands must remain accepted")
+	}
+}
+
+func TestIsCommandForBotAllowsMatchingUsername(t *testing.T) {
+	if !isCommandForBot("/status@panel_bot", "Panel_Bot") {
+		t.Fatal("commands targeted to this bot must be accepted")
+	}
+}
+
+func TestIsCommandForBotRejectsOtherUsername(t *testing.T) {
+	if isCommandForBot("/status@other_bot", "panel_bot") {
+		t.Fatal("commands targeted to another bot must be ignored")
+	}
+}
+
+func TestIsCommandForBotKeepsLegacyBehaviorWhenUsernameUnavailable(t *testing.T) {
+	if !isCommandForBot("/status@panel_bot", "") {
+		t.Fatal("commands must remain accepted when the current bot username is unavailable")
+	}
+}