summaryrefslogtreecommitdiff
path: root/Omni/Agent/Telegram
diff options
context:
space:
mode:
authorBen Sima <ben@bensima.com>2025-12-13 09:14:39 -0500
committerBen Sima <ben@bensima.com>2025-12-13 09:14:39 -0500
commited629a3335c6c5a172322a8d7387f0c6990b0ae5 (patch)
treec2c1676ad1593143c12a082f723f46af5a3a67c2 /Omni/Agent/Telegram
parent5ba051535138630b333657a6540728a9148c766a (diff)
feat: only allow whitelisted users to add bot to groups
When the bot is added to a group, check if the user who added it is in the whitelist. If not, send a message explaining and leave the group immediately. This prevents unauthorized users from bypassing DM access controls by adding the bot to a group.
Diffstat (limited to 'Omni/Agent/Telegram')
-rw-r--r--Omni/Agent/Telegram/Types.hs50
1 files changed, 50 insertions, 0 deletions
diff --git a/Omni/Agent/Telegram/Types.hs b/Omni/Agent/Telegram/Types.hs
index d240786..aaea65b 100644
--- a/Omni/Agent/Telegram/Types.hs
+++ b/Omni/Agent/Telegram/Types.hs
@@ -19,10 +19,12 @@ module Omni.Agent.Telegram.Types
TelegramPhoto (..),
TelegramVoice (..),
TelegramReplyMessage (..),
+ BotAddedToGroup (..),
ChatType (..),
-- * Parsing
parseUpdate,
+ parseBotAddedToGroup,
parseDocument,
parseLargestPhoto,
parsePhotoSize,
@@ -323,6 +325,14 @@ instance Aeson.FromJSON TelegramReplyMessage where
<*> (v .:? "from_last_name")
<*> (v .:? "text" .!= "")
+data BotAddedToGroup = BotAddedToGroup
+ { bagUpdateId :: Int,
+ bagChatId :: Int,
+ bagAddedByUserId :: Int,
+ bagAddedByFirstName :: Text
+ }
+ deriving (Show, Eq, Generic)
+
data ChatType = Private | Group | Supergroup | Channel
deriving (Show, Eq, Generic)
@@ -461,6 +471,46 @@ parseUpdate val = do
tmReplyTo = replyTo
}
+parseBotAddedToGroup :: Text -> Aeson.Value -> Maybe BotAddedToGroup
+parseBotAddedToGroup botUsername val = do
+ Aeson.Object obj <- pure val
+ updateId <- case KeyMap.lookup "update_id" obj of
+ Just (Aeson.Number n) -> Just (round n)
+ _ -> Nothing
+ Aeson.Object msgObj <- KeyMap.lookup "message" obj
+ Aeson.Object chatObj <- KeyMap.lookup "chat" msgObj
+ chatId <- case KeyMap.lookup "id" chatObj of
+ Just (Aeson.Number n) -> Just (round n)
+ _ -> Nothing
+ let chatType = case KeyMap.lookup "type" chatObj of
+ Just (Aeson.String t) -> t
+ _ -> "private"
+ guard (chatType == "group" || chatType == "supergroup")
+ Aeson.Object fromObj <- KeyMap.lookup "from" msgObj
+ addedByUserId <- case KeyMap.lookup "id" fromObj of
+ Just (Aeson.Number n) -> Just (round n)
+ _ -> Nothing
+ addedByFirstName <- case KeyMap.lookup "first_name" fromObj of
+ Just (Aeson.String s) -> Just s
+ _ -> Nothing
+ Aeson.Array newMembers <- KeyMap.lookup "new_chat_members" msgObj
+ let botWasAdded = any (isBotUser botUsername) (toList newMembers)
+ guard botWasAdded
+ pure
+ BotAddedToGroup
+ { bagUpdateId = updateId,
+ bagChatId = chatId,
+ bagAddedByUserId = addedByUserId,
+ bagAddedByFirstName = addedByFirstName
+ }
+ where
+ isBotUser :: Text -> Aeson.Value -> Bool
+ isBotUser username (Aeson.Object userObj) =
+ case KeyMap.lookup "username" userObj of
+ Just (Aeson.String u) -> Text.toLower u == Text.toLower username
+ _ -> False
+ isBotUser _ _ = False
+
parseDocument :: Aeson.Object -> Maybe TelegramDocument
parseDocument docObj = do
fileId <- case KeyMap.lookup "file_id" docObj of