From 1db5983ed53a57568c67304ca01e005b92b4e3ed Mon Sep 17 00:00:00 2001 From: Ioannis Dressos <96877388+idressos@users.noreply.github.com> Date: Wed, 8 Jul 2026 12:13:30 +0300 Subject: [PATCH] Guard Telegram flood-wait maps with a mutex to prevent data races --- telegram/bot.go | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/telegram/bot.go b/telegram/bot.go index 7842f63..12e2476 100644 --- a/telegram/bot.go +++ b/telegram/bot.go @@ -28,6 +28,7 @@ var ( floodWait = make(map[int64]int64) floodMessageSent = make(map[int64]struct{}) + floodMutex sync.Mutex ) func Start(initDeps TgBotInitDependencies) (err error) { @@ -79,11 +80,25 @@ func Start(initDeps TgBotInitDependencies) (err error) { for update := range updatesChan { if update.Message != nil { userid := update.Message.Chat.ID - if _, wait := floodWait[userid]; wait { + + floodMutex.Lock() + _, wait := floodWait[userid] + alreadyNotified := false + if wait { if _, notified := floodMessageSent[userid]; notified { + alreadyNotified = true + } else { + floodMessageSent[userid] = struct{}{} + } + } else { + floodWait[userid] = time.Now().Unix() + } + floodMutex.Unlock() + + if wait { + if alreadyNotified { continue } - floodMessageSent[userid] = struct{}{} _, err := bot.SendMessage( fmt.Sprintf("You can only request your configs once per %d minutes", FloodWait), userid, @@ -95,7 +110,6 @@ func Start(initDeps TgBotInitDependencies) (err error) { } continue } - floodWait[userid] = time.Now().Unix() failed := initDeps.SendRequestedConfigsToTelegram(initDeps.DB, userid) if len(failed) > 0 { @@ -126,12 +140,14 @@ func SendConfig(userid int64, clientName string, confData, qrData []byte, ignore return fmt.Errorf("telegram bot is not configured or not available") } - if _, wait := floodWait[userid]; wait && !ignoreFloodWait { - return fmt.Errorf("this client already got their config less than %d minutes ago", FloodWait) - } - if !ignoreFloodWait { + floodMutex.Lock() + if _, wait := floodWait[userid]; wait { + floodMutex.Unlock() + return fmt.Errorf("this client already got their config less than %d minutes ago", FloodWait) + } floodWait[userid] = time.Now().Unix() + floodMutex.Unlock() } qrAttachment := echotron.NewInputFileBytes("qr.png", qrData) @@ -152,10 +168,12 @@ func SendConfig(userid int64, clientName string, confData, qrData []byte, ignore func updateFloodWait() { thresholdTS := time.Now().Unix() - 60*int64(FloodWait) + floodMutex.Lock() for userid, ts := range floodWait { if ts < thresholdTS { delete(floodWait, userid) delete(floodMessageSent, userid) } } + floodMutex.Unlock() }