မောင်သုည

Telegram Bot Setup Guide

Master Control Bot Setup Guide V2

၁။ Telegram Bot Token ရယူခြင်း

Master Control Bot အတွက် Telegram Bot Token ကို @BotFather မှ ရယူရပါမည်။

  1. 1 Telegram တွင် @BotFather ကို ရှာဖွေပြီး /start command ပို့ပါ။
  2. 2 /newbot command ကို ပို့ပြီး Bot အသစ်တစ်ခု ဖန်တီးပါ။
  3. 3 Bot အတွက် နာမည် (ဥပမာ: LicenseMasterBot) ပေးပါ။
  4. 4 Bot အတွက် Username (ဥပမာ: LicenseMaster_bot) ပေးပါ။ Username သည် _bot ဖြင့် ဆုံးရပါမည်။
  5. 5 BotFather မှ ပေးသော HTTP API Token ကို ကူးယူပါ။ ဤ Token သည် အောက်ပါအတိုင်း ဖြစ်ပါမည်။
    123456789:ABCDE-FGHIJ-KLMNO-PQRST-UVWXY

၂။ Cloudflare Pages Project အသစ်တည်ဆောက်ခြင်း

Master Control Bot အတွက် Cloudflare Pages Project အသစ်တစ်ခု တည်ဆောက်ပါ။

  1. 1 Cloudflare Account သို့ Login ဝင်ပါ။
  2. 2 Dashboard မှ Workers & Pages သို့ သွားပါ။
  3. 3 Create application ကို နှိပ်ပါ။
  4. 4 Connect to Git ကို ရွေးချယ်ပြီး GitHub Account ကို ချိတ်ဆက်ပါ။
  5. 5 သင့်ရဲ့ Master Control Bot Code ကို သင့်ရဲ့ GitHub Repository သို့ Fork လုပ်ပါ။ (ဤနေရာတွင် သင့်ရဲ့ Control Bot Code Repository Link ကို ထည့်ပါ)
  6. 6 Fork လုပ်ထားသော Repository ကို ရွေးချယ်ပြီး Begin setup ကို နှိပ်ပါ။
  7. 7 Project Name ကို ထည့်ပါ။ (ဥပမာ: master-control)

၃။ Environment Variables များ သတ်မှတ်ခြင်း

Project Setup အဆင့်တွင် Build settings အောက်ရှိ Environment Variables များတွင် အောက်ပါ Variables များကို ထည့်သွင်းပေးရပါမည်။

၄။ Control Bot Code ထည့်သွင်းခြင်း

သင့်ရဲ့ GitHub Repository ထဲရှိ functions/_middleware.js ဖိုင်ကို အောက်ပါ code ဖြင့် အစားထိုးပါ။

// This is the complete Telegram Bot code, adapted for Cloudflare Pages Function. // FINAL FIX: Implemented precise link blocking. // - Allows all VPN links (including Play Store VPN app links). // - Mutes ONLY the specific game/shopping domains and their specific Play Store/App Store app IDs provided by the user. // - Admin/Owner messages are still exempt from spam detection. const TELEGRAM_API = "https://api.telegram.org/bot"; // အလိုအလျောက် Mute လုပ်မည့် Website Domains များ (Games/Shopping) // ဤစာရင်းရှိ Domains များပါဝင်သော မည်သည့် Link ကိုမဆို Mute ပါမည်။ const BLOCKED_DOMAINS = [ "temu.com", "shein.com", "shopee.com", "aliexpress.com", "wish.com", "lazada.com", "daraz.pk", "gameloop.com", "bluestacks.com", "fortnite.com", "roblox.com", "minecraft.net", "garena.com", "pubgmobile.com", "callofduty.com", "clashofclans.com", "mobilelegends.com", "genshinimpact.mihoyo.com", "freefire.com", "fivestarskm.com", // Example gambling site "fivestarskm777.t.me", // Specific Telegram channel link "facebook.com/profile.php?id=100075308733678", // Example specific gambling Facebook profile ]; // Play Store နှင့် Apple App Store မှ Mute လုပ်မည့် Specific App IDs များ // play.google.com/store/apps/details?id= နှင့် apps.apple.com/us/app/id တို့မှ အက်ပ်အိုင်ဒီများကို Mute ပါမည်။ const BLOCKED_APP_IDS = [ "com.einnovation.temu", // Temu "com.zhiliaoapp.musically", // TikTok (often associated with e-commerce) "com.shein.sheinlive", // Shein "com.lazada.android", // Lazada "com.shopee.th", // Shopee (example, can be specific to country) "com.alibaba.aliexpresshd", // AliExpress "com.contextlogic.wish", // Wish "com.tencent.ig", // PUBG Mobile "com.garena.game.kgid", // Garena Free Fire "com.mojang.minecraftpe", // Minecraft "com.roblox.client", // Roblox "com.mobile.legends", // Mobile Legends: Bang Bang "com.supercell.clashofclans", // Clash of Clans "com.activision.callofduty.shooter", // Call of Duty Mobile "com.mihoyo.genshinimpact", // Genshin Impact "com.garena.game.sm", // Garena (general client if needed) ]; // အလိုအလျောက် Mute လုပ်မည့် Keywords များ စာရင်း (Case-insensitive) const BLOCKED_KEYWORDS_REGEX = [ /\\b2D\\b/i, /\\b3D\\b/i, ]; // Admin User ID (your Telegram User ID) // Replace with your actual Telegram User ID (e.g., 7576434717) const adminUserId = "7576434717"; // <--- REPLACE WITH YOUR ADMIN USER ID // --- Helper Functions --- async function sendMessage(token, chat_id, text, parse_mode = 'HTML', reply_markup = null) { const apiUrl = \`${TELEGRAM_API}\${token}/sendMessage\`; const payload = { chat_id: chat_id, text: text, parse_mode: parse_mode, disable_web_page_preview: true }; if (reply_markup) { payload.reply_markup = reply_markup; } try { console.log(\`[sendMessage] Sending message to \${chat_id}: \${text.substring(0, 50)}...\`); const response = await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); const result = await response.json(); if (!response.ok) { console.error(\`[sendMessage] Failed to send message: \${response.status} \${JSON.stringify(result)}\`); } return result; } catch (error) { console.error("[sendMessage] Error sending message:", error); return { ok: false, error_code: 500, description: error.message }; } } async function deleteMessage(token, chat_id, message_id) { const apiUrl = \`${TELEGRAM_API}\${token}/deleteMessage\`; const payload = { chat_id: chat_id, message_id: message_id }; try { console.log(\`[deleteMessage] Attempting to delete message \${message_id} in chat \${chat_id}.\`); const response = await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); if (!response.ok) { const errorText = await response.text(); console.error(\`[deleteMessage] Failed to delete message \${message_id}: \${response.status} \${errorText}\`); } else { console.log(\`[deleteMessage] Message \${message_id} deleted successfully.\`); } } catch (error) { console.error(\`[deleteMessage] Error deleting message \${message_id}:\`, error); } } async function getMe(token) { const apiUrl = \`${TELEGRAM_API}\${token}/getMe\`; try { console.log("[getMe] Fetching bot info."); const response = await fetch(apiUrl); const result = await response.json(); if (response.ok && result.ok) { console.log("[getMe] Bot info fetched successfully."); return result.result; } else { console.error(\`[getMe] Failed to get bot info: \${result.description}\`); return null; } } catch (error) { console.error(\`[getMe] Error getting bot info:\`, error); return null; } } async function restrictChatMember(token, chat_id, user_id, until_date = 0) { const apiUrl = \`${TELEGRAM_API}\${token}/restrictChatMember\`; const payload = { chat_id: chat_id, user_id: user_id, permissions: { can_send_messages: false, can_send_audios: false, can_send_documents: false, can_send_photos: false, can_send_videos: false, can_send_video_notes: false, can_send_polls: false, can_send_other_messages: false, can_add_web_page_previews: false, can_change_info: false, can_invite_users: false, can_pin_messages: false, can_send_voice_notes: false }, until_date: until_date }; try { console.log(\`[restrictChatMember] Attempting to restrict user \${user_id} in chat \${chat_id}. Payload: \${JSON.stringify(payload)}\`); const response = await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); const result = await response.json(); if (!response.ok || !result.ok) { console.error(\`[restrictChatMember] Failed to restrict chat member \${user_id}: \${result.description || JSON.stringify(result)}\`); return false; } console.log(\`[restrictChatMember] User \${user_id} restricted successfully. Result: \${JSON.stringify(result)}\`); return true; } catch (error) { console.error(\`[restrictChatMember] Error restricting chat member \${user_id}:\`, error); return false; } } async function unrestrictChatMember(token, chat_id, user_id) { const apiUrl = \`${TELEGRAM_API}\${token}/restrictChatMember\`; const payload = { chat_id: chat_id, user_id: user_id, permissions: { can_send_messages: true, can_send_audios: true, can_send_documents: true, can_send_photos: true, can_send_videos: true, can_send_video_notes: true, can_send_polls: true, can_send_other_messages: true, can_add_web_page_previews: true, can_change_info: true, can_invite_users: true, can_pin_messages: true, can_send_voice_notes: true }, until_date: 0 }; try { console.log(\`[unrestrictChatMember] Attempting to UN-RESTRICT user \${user_id} in chat \${chat_id}. Payload: \${JSON.stringify(payload)}\`); const response = await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); const result = await response.json(); if (!response.ok || !result.ok) { console.error(\`[unrestrictChatMember] Failed to UN-RESTRICT chat member \${user_id}: \${result.description || JSON.stringify(result)}\`); return false; } console.log(\`[unrestrictChatMember] User \${user_id} UN-RESTRICTED successfully. Result: \${JSON.stringify(result)}\`); return true; } catch (error) { console.error(\`[unrestrictChatMember] Error un-restricting chat member \${user_id}:\`, error); return false; } } async function kickChatMember(token, chat_id, user_id, until_date = 0) { const apiUrl = \`${TELEGRAM_API}\${token}/kickChatMember\`; const payload = { chat_id: chat_id, user_id: user_id, until_date: until_date }; try { console.log(\`[kickChatMember] Attempting to kick user \${user_id} from chat \${chat_id}.\`); const response = await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); const result = await response.json(); if (!response.ok || !result.ok) { console.error(\`[kickChatMember] Failed to kick chat member \${user_id}: \${result.description}\`); return false; } return true; } catch (error) { console.error(\`[kickChatMember] Error kicking chat member \${user_id}:\`, error); return false; } } async function unbanChatMember(token, chat_id, user_id) { const apiUrl = \`${TELEGRAM_API}\${token}/unbanChatMember\`; const payload = { chat_id: chat_id, user_id: user_id, only_if_banned: true }; try { console.log(\`[unbanChatMember] Attempting to unban user \${user_id} from chat \${chat_id}.\`); const response = await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); const result = await response.json(); if (!response.ok || !result.ok) { console.error(\`[unbanChatMember] Failed to unban chat member \${user_id}: \${result.description}\`); return false; } return true; } catch (error) { console.error(\`[unbanChatMember] Error unban chat member \${user_id}:\`, error); return false; } } async function answerCallbackQuery(token, callbackQueryId, text, showAlert = false) { const apiUrl = \`${TELEGRAM_API}\${token}/answerCallbackQuery\`; const payload = { callback_query_id: callbackQueryId, text: text, show_alert: showAlert }; try { console.log(\`[answerCallbackQuery] Answering callback query \${callbackQueryId}.\`); await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); } catch (error) { console.error("[answerCallbackQuery] Error answering callback query:", error); } } async function editMessageText(token, chatId, messageId, text, parseMode = 'HTML', reply_markup = null) { const apiUrl = \`${TELEGRAM_API}\${token}/editMessageText\`; const payload = { chat_id: chatId, message_id: messageId, text: text, parse_mode: parseMode, disable_web_page_previews: true }; if (reply_markup) { payload.reply_markup = reply_markup; } try { console.log(\`[editMessageText] Editing message \${messageId} in chat \${chatId}.\`); const response = await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); if (!response.ok) { const errorText = await response.text(); console.error(\`[editMessageText] Failed to edit message: \${response.status} \${errorText}\`); } else { console.log(\`[editMessageText] Message \${messageId} edited successfully.\`); } } catch (error) { console.error("Error editing message:", error); } } async function getChatMember(token, chatId, userId) { const apiUrl = \`${TELEGRAM_API}\${token}/getChatMember\`; const payload = { chat_id: chatId, user_id: userId }; try { console.log(\`[getChatMember] Fetching info for user \${userId} in chat \${chatId}.\`); const response = await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); const result = await response.json(); if (response.ok && result.ok) { console.log(\`[getChatMember] Info fetched for user \${userId}.\`); return result.result; } else { console.error(\`[getChatMember] Failed to get chat member \${userId}: \${result.description}\`); return null; } } catch (error) { console.error(\`[getChatMember] Error getting chat member \${userId}:\`, error); return null; } } async function isUserAdmin(chatId, userId, token, isAnonymousSender = false, senderChatId = null) { console.log(\`[isUserAdmin] Checking admin status for user \${userId} in chat \${chatId}. Anonymous: \${isAnonymousSender}, SenderChatId: \${senderChatId}\`); if (isAnonymousSender && senderChatId === chatId) { console.log(\`[isUserAdmin] Recognized anonymous admin action from sender_chat_id: \${senderChatId}.\`); return true; } const apiUrl = \`${TELEGRAM_API}\${token}/getChatAdministrators\`; try { console.log(\`[isUserAdmin] Fetching chat administrators for chat \${chatId}.\`); const response = await fetch(apiUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ chat_id: chatId }) }); const result = await response.json(); if (!response.ok || !result.ok) { console.error(\`[isUserAdmin] Failed to get chat administrators for chat \${chatId}: \${result.description}\`); return false; } const administrators = result.result; for (const admin of administrators) { if (admin.user.id === userId && (admin.status === 'administrator' || admin.status === 'creator')) { console.log(\`[isUserAdmin] User \${userId} is an admin.\`); return true; } } console.log(\`[isUserAdmin] User \${userId} is NOT an admin.\`); return false; } catch (error) { console.error(\`[isUserAdmin] Error checking user admin status for chat \${chatId}, user \${userId}:\`, error); return false; } } async function getUserBotData(botKey, env) { if (!env.BOT_USERS_DB) { console.warn("[getUserBotData] BOT_USERS_DB KV namespace is not bound. Cannot retrieve bot user data."); return null; } try { const userData = await env.BOT_USERS_DB.get(botKey, { type: 'json' }); console.log(\`[getUserBotData] Retrieved data for key \${botKey}: \${JSON.stringify(userData)}\`); return userData; } catch (error) { console.error(\`[getUserBotData] Error retrieving bot data for key \${botKey}:\`, error); return null; } } async function setUserBotData(botKey, data, env) { if (!env.BOT_USERS_DB) { console.warn("[setUserBotData] BOT_USERS_DB KV namespace is not bound. Cannot set bot user data."); return false; } try { await env.BOT_USERS_DB.put(botKey, JSON.stringify(data)); console.log(\`[setUserBotData] Stored data for key \${botKey}: \${JSON.stringify(data)}\`); return true; } catch (error) { console.error(\`[setUserBotData] Error setting bot data for key \${botKey}:\`, error); return false; } } async function deleteUserBotData(botKey, env) { if (!env.BOT_USERS_DB) { console.warn("[deleteUserBotData] BOT_USERS_DB KV namespace is not bound. Cannot delete bot user data."); return false; } try { await env.BOT_USERS_DB.delete(botKey); console.log(\`[deleteUserBotData] Deleted data for key \${botKey}.\`); return true; } catch (error) { console.error(\`[deleteUserBotData] Error deleting bot data for key \${botKey}:\`, error); return false; } } // --- Command Handlers --- async function handleStartCommand(message, token) { const chatId = message.chat.id; console.log(\`[handleStartCommand] Received /start command from chat \${chatId}.\`); await sendMessage(token, chatId, 'မင်္ဂလာပါ! ကျွန်တော်က Bot Key Management Bot ပါ။ Bot Key များကို ထုတ်လုပ်ရန်၊ စီမံရန်နှင့် စစ်ဆေးရန် အသုံးပြုနိုင်ပါသည်။'); } async function handleGenerateKeyCommand(message, token, env) { const chatId = message.chat.id; const fromUser = message.from; const args = message.text.split(' '); console.log(\`[handleGenerateKeyCommand] Received /generatekey command from user \${fromUser.id}.\`); if (fromUser.id.toString() !== adminUserId) { console.warn(\`[handleGenerateKeyCommand] Unauthorized access attempt by user \${fromUser.id}.\`); await sendMessage(token, chatId, "🚫 ဤ command ကို အသုံးပြုရန် ခွင့်ပြုချက်မရှိပါ။"); return; } let duration = 'permanent'; // Default to permanent let description = ''; if (args.length > 1) { duration = args[1].toLowerCase(); if (args.length > 2) { description = args.slice(2).join(' '); } } const newKey = crypto.randomUUID(); let expiresAt = null; const now = new Date(); switch (duration) { case '10min': expiresAt = new Date(now.getTime() + 10 * 60 * 1000); break; case '1h': expiresAt = new Date(now.getTime() + 1 * 60 * 60 * 1000); break; case '1d': expiresAt = new Date(now.getTime() + 1 * 24 * 60 * 60 * 1000); break; case '3d': expiresAt = new Date(now.getTime() + 3 * 24 * 60 * 60 * 1000); break; case '1w': expiresAt = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); break; case '1m': case '1month': expiresAt = new Date(now.setMonth(now.getMonth() + 1)); break; case '3m': case '3month': expiresAt = new Date(now.setMonth(now.getMonth() + 3)); break; case '6m': case '6month': expiresAt = new Date(now.setMonth(now.getMonth() + 6)); break; case '1y': case '1year': expiresAt = new Date(now.setFullYear(now.getFullYear() + 1)); break; case 'permanent': expiresAt = null; break; // No expiration default: await sendMessage(token, chatId, "Invalid duration. Usage: /generatekey [10min|1h|1d|3d|1w|1m|3m|6m|1y|permanent] [description]"); return; } const keyData = { key: newKey, created_at: new Date().toISOString(), expires_at: expiresAt ? expiresAt.toISOString() : null, active: true, description: description }; const success = await setUserBotData(newKey, keyData, env); if (success) { let expiryMessage = "အမြဲတမ်းအသုံးပြုနိုင်ပါမည်။"; if (expiresAt) { const thailandTime = expiresAt.toLocaleString('en-US', { timeZone: 'Asia/Bangkok', year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: true }); const myanmarTime = expiresAt.toLocaleString('en-US', { timeZone: 'Asia/Yangon', year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: true }); expiryMessage = `${thailandTime} (Thailand)\n${myanmarTime} (Myanmar)`; } await sendMessage(token, chatId, `✅ Bot Key အသစ် ထုတ်လုပ်ပြီးပါပြီ:\n\n${newKey}\n\nStatus: Active ✅\nExpires: ${expiryMessage}\nDescription: ${description || 'N/A'}`); } else { await sendMessage(token, chatId, "❌ Bot Key ထုတ်လုပ်ခြင်း မအောင်မြင်ပါ။"); } } async function handleListKeysCommand(message, token, env) { const chatId = message.chat.id; const fromUser = message.from; console.log(`[handleListKeysCommand] Received /listkeys command from user ${fromUser.id}.`); if (fromUser.id.toString() !== adminUserId) { console.warn(`[handleListKeysCommand] Unauthorized access attempt by user ${fromUser.id}.`); await sendMessage(token, chatId, "🚫 ဤ command ကို အသုံးပြုရန် ခွင့်ပြုချက်မရှိပါ။"); return; } if (!env.BOT_USERS_DB) { await sendMessage(token, chatId, "Error: BOT_USERS_DB KV namespace is not bound."); return; } const { keys } = await env.BOT_USERS_DB.list(); let responseText = "Bot Keys List:\n\n"; if (keys.length === 0) { responseText += "No keys found."; } else { for (const keyInfo of keys) { const keyData = await getUserBotData(keyInfo.name, env); if (keyData) { const expiresAt = keyData.expires_at ? new Date(keyData.expires_at) : null; let expiryMessage = "အမြဲတမ်းအသုံးပြုနိုင်ပါမည်။"; if (expiresAt) { const now = new Date(); const isActive = keyData.active && (expiresAt > now || expiresAt === null); const thailandTime = expiresAt.toLocaleString('en-US', { timeZone: 'Asia/Bangkok', year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: true }); const myanmarTime = expiresAt.toLocaleString('en-US', { timeZone: 'Asia/Yangon', year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: true }); expiryMessage = `${thailandTime} (Thailand)\n${myanmarTime} (Myanmar)`; responseText += `Key: ${keyData.key}\n`; responseText += `Status: ${isActive ? 'Active ✅' : 'Inactive ❌'}\n`; responseText += `Expires: ${expiryMessage}\n`; responseText += `Description: ${keyData.description || 'N/A'}\n\n`; } else { // Permanent key responseText += `Key: ${keyData.key}\n`; responseText += `Status: ${keyData.active ? 'Active ✅' : 'Inactive ❌'}\n`; responseText += `Expires: အမြဲတမ်းအသုံးပြုနိုင်ပါမည်။\n`; responseText += `Description: ${keyData.description || 'N/A'}\n\n`; } } } } await sendMessage(token, chatId, responseText); } async function handleActivateKeyCommand(message, token, env) { const chatId = message.chat.id; const fromUser = message.from; const args = message.text.split(' '); console.log(`[handleActivateKeyCommand] Received /activatekey command from user ${fromUser.id}.`); if (fromUser.id.toString() !== adminUserId) { console.warn(`[handleActivateKeyCommand] Unauthorized access attempt by user ${fromUser.id}.`); await sendMessage(token, chatId, "🚫 ဤ command ကို အသုံးပြုရန် ခွင့်ပြုချက်မရှိပါ။"); return; } if (args.length < 2) { await sendMessage(token, chatId, "Usage: /activatekey <key_value>"); return; } const keyToActivate = args[1]; const keyData = await getUserBotData(keyToActivate, env); if (!keyData) { await sendMessage(token, chatId, `❌ Bot Key ${keyToActivate} ကို ရှာမတွေ့ပါ။`); return; } keyData.active = true; const success = await setUserBotData(keyToActivate, keyData, env); if (success) { await sendMessage(token, chatId, `✅ Bot Key ${keyToActivate} ကို Activate လုပ်ပြီးပါပြီ။`); } else { await sendMessage(token, chatId, `❌ Bot Key ${keyToActivate} ကို Activate လုပ်ခြင်း မအောင်မြင်ပါ။`); } } async function handleDeactivateKeyCommand(message, token, env) { const chatId = message.chat.id; const fromUser = message.from; const args = message.text.split(' '); console.log(`[handleDeactivateKeyCommand] Received /deactivatekey command from user ${fromUser.id}.`); if (fromUser.id.toString() !== adminUserId) { console.warn(`[handleDeactivateKeyCommand] Unauthorized access attempt by user ${fromUser.id}.`); await sendMessage(token, chatId, "🚫 ဤ command ကို အသုံးပြုရန် ခွင့်ပြုချက်မရှိပါ။"); return; } if (args.length < 2) { await sendMessage(token, chatId, "Usage: /deactivatekey <key_value>"); return; } const keyToDeactivate = args[1]; const keyData = await getUserBotData(keyToDeactivate, env); if (!keyData) { await sendMessage(token, chatId, `❌ Bot Key ${keyToDeactivate} ကို ရှာမတွေ့ပါ။`); return; } keyData.active = false; const success = await setUserBotData(keyToDeactivate, keyData, env); if (success) { await sendMessage(token, chatId, `✅ Bot Key ${keyToDeactivate} ကို Deactivate လုပ်ပြီးပါပြီ။`); } else { await sendMessage(token, chatId, `❌ Bot Key ${keyToDeactivate} ကို Deactivate လုပ်ခြင်း မအောင်မြင်ပါ။`); } } async function handleRenewKeyCommand(message, token, env) { const chatId = message.chat.id; const fromUser = message.from; const args = message.text.split(' '); console.log(`[handleRenewKeyCommand] Received /renewkey command from user ${fromUser.id}.`); if (fromUser.id.toString() !== adminUserId) { console.warn(`[handleRenewKeyCommand] Unauthorized access attempt by user ${fromUser.id}.`); await sendMessage(token, chatId, "🚫 ဤ command ကို အသုံးပြုရန် ခွင့်ပြုချက်မရှိပါ။"); return; } if (args.length < 3) { await sendMessage(token, chatId, "Usage: /renewkey <key_value> <duration> (e.g., 10min, 1h, 1d, 3d, 1w, 1m, 3m, 6m, 1y)"); return; } const keyToExtend = args[1]; const duration = args[2].toLowerCase(); const keyData = await getUserBotData(keyToExtend, env); if (!keyData) { await sendMessage(token, chatId, `❌ Bot Key ${keyToExtend} ကို ရှာမတွေ့ပါ။`); return; } let newExpiresAt = keyData.expires_at ? new Date(keyData.expires_at) : new Date(); if (!keyData.expires_at) { // If it was permanent, set current time as base newExpiresAt = new Date(); } switch (duration) { case '10min': newExpiresAt.setMinutes(newExpiresAt.getMinutes() + 10); break; case '1h': newExpiresAt.setHours(newExpiresAt.getHours() + 1); break; case '1d': newExpiresAt.setDate(newExpiresAt.getDate() + 1); break; case '3d': newExpiresAt.setDate(newExpiresAt.getDate() + 3); break; case '1w': newExpiresAt.setDate(newExpiresAt.getDate() + 7); break; case '1m': case '1month': newExpiresAt.setMonth(newExpiresAt.getMonth() + 1); break; case '3m': case '3month': newExpiresAt.setMonth(newExpiresAt.getMonth() + 3); break; case '6m': case '6month': newExpiresAt.setMonth(newExpiresAt.getMonth() + 6); break; case '1y': newExpiresAt.setFullYear(newExpiresAt.getFullYear() + 1); break; default: await sendMessage(token, chatId, "Invalid duration. Usage: /renewkey <key_value> <duration> (e.g., 10min, 1h, 1d, 3d, 1w, 1m, 3m, 6m, 1y)"); return; } keyData.expires_at = newExpiresAt.toISOString(); keyData.active = true; // Automatically activate when extending const success = await setUserBotData(keyToExtend, keyData, env); if (success) { const thailandTime = newExpiresAt.toLocaleString('en-US', { timeZone: 'Asia/Bangkok', year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: true }); const myanmarTime = newExpiresAt.toLocaleString('en-US', { timeZone: 'Asia/Yangon', year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: true }); await sendMessage(token, chatId, `✅ Bot Key ${keyToExtend} ၏ သက်တမ်းကို တိုးမြှင့်ပြီးပါပြီ။\n\nသက်တမ်းကုန်ဆုံးရက်အသစ်:\n${thailandTime} (Thailand)\n${myanmarTime} (Myanmar)`); } else { await sendMessage(token, chatId, `❌ Bot Key ${keyToExtend} ၏ သက်တမ်းကို တိုးမြှင့်ခြင်း မအောင်မြင်ပါ။`); } } async function handleSetResetKeyCommand(message, token, env) { const chatId = message.chat.id; const fromUser = message.from; const args = message.text.split(' '); console.log(`[handleSetResetKeyCommand] Received /setresetkey command from user ${fromUser.id}.`); if (fromUser.id.toString() !== adminUserId) { console.warn(`[handleSetResetKeyCommand] Unauthorized access attempt by user ${fromUser.id}.`); await sendMessage(token, chatId, "🚫 ဤ command ကို အသုံးပြုရန် ခွင့်ပြုချက်မရှိပါ။"); return; } if (args.length < 3) { await sendMessage(token, chatId, "Usage: /setresetkey <key_value> <duration> (e.g., 10min, 1h, 1d, 3d, 1w, 1m, 3m, 6m, 1y, permanent)"); return; } const keyToSet = args[1]; const duration = args[2].toLowerCase(); const keyData = await getUserBotData(keyToSet, env); if (!keyData) { await sendMessage(token, chatId, `❌ Bot Key ${keyToSet} ကို ရှာမတွေ့ပါ။`); return; } let newExpiresAt = new Date(); // Always reset from now switch (duration) { case '10min': newExpiresAt.setMinutes(newExpiresAt.getMinutes() + 10); break; case '1h': newExpiresAt.setHours(newExpiresAt.getHours() + 1); break; case '1d': newExpiresAt.setDate(newExpiresAt.getDate() + 1); break; case '3d': newExpiresAt.setDate(newExpiresAt.getDate() + 3); break; case '1w': newExpiresAt.setDate(newExpiresAt.getDate() + 7); break; case '1m': case '1month': newExpiresAt.setMonth(newExpiresAt.getMonth() + 1); break; case '3m': case '3month': newExpiresAt.setMonth(newExpiresAt.getMonth() + 3); break; case '6m': case '6month': newExpiresAt.setMonth(newExpiresAt.getMonth() + 6); break; case '1y': newExpiresAt.setFullYear(newExpiresAt.getFullYear() + 1); break; case 'permanent': newExpiresAt = null; break; // No expiration default: await sendMessage(token, chatId, "Invalid duration. Usage: /setresetkey <key_value> <duration> (e.g., 10min, 1h, 1d, 3d, 1w, 1m, 3m, 6m, 1y, permanent)"); return; } keyData.expires_at = newExpiresAt ? newExpiresAt.toISOString() : null; keyData.active = true; // Automatically activate when setting new expiry const success = await setUserBotData(keyToSet, keyData, env); if (success) { let expiryMessage = "အမြဲတမ်းအသုံးပြုနိုင်ပါမည်။"; if (newExpiresAt) { const thailandTime = newExpiresAt.toLocaleString('en-US', { timeZone: 'Asia/Bangkok', year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: true }); const myanmarTime = newExpiresAt.toLocaleString('en-US', { timeZone: 'Asia/Yangon', year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: true }); expiryMessage = `${thailandTime} (Thailand)\n${myanmarTime} (Myanmar)`; } await sendMessage(token, chatId, `✅ Bot Key ${keyToSet} ၏ သက်တမ်းကို အခုအချိန်ကစပြီး ပြန်လည်သတ်မှတ်ပြီးပါပြီ။\n\nသက်တမ်းကုန်ဆုံးရက်အသစ်:\n${expiryMessage}`); } else { await sendMessage(token, chatId, `❌ Bot Key ${keyToSet} ၏ သက်တမ်းကို ပြန်လည်သတ်မှတ်ခြင်း မအောင်မြင်ပါ။`); } } async function handleDeleteKeyCommand(message, token, env) { const chatId = message.chat.id; const fromUser = message.from; const args = message.text.split(' '); console.log(`[handleDeleteKeyCommand] Received /deletekey command from user ${fromUser.id}.`); if (fromUser.id.toString() !== adminUserId) { console.warn(`[handleDeleteKeyCommand] Unauthorized access attempt by user ${fromUser.id}.`); await sendMessage(token, chatId, "🚫 ဤ command ကို အသုံးပြုရန် ခွင့်ပြုချက်မရှိပါ။"); return; } if (args.length < 2) { await sendMessage(token, chatId, "Usage: /deletekey <key_value>"); return; } const keyToDelete = args[1]; const success = await deleteUserBotData(keyToDelete, env); if (success) { await sendMessage(token, chatId, `✅ Bot Key ${keyToDelete} ကို ဖျက်လိုက်ပါပြီ။`); } else { await sendMessage(token, chatId, `❌ Bot Key ${keyToDelete} ကို ဖျက်ခြင်း မအောင်မြင်ပါ။`); } } // --- Main Pages Function Entry Point --- export async function onRequest(context) { const { request, env } = context; const token = env.TELEGRAM_BOT_TOKEN; // Your Control Bot's token console.log(`[onRequest] Received request: ${request.method} ${request.url}`); let requestBody = {}; try { if (request.method === "POST" && request.headers.get("content-type")?.includes("application/json")) { requestBody = await request.clone().json(); console.log("[onRequest] Full incoming request body:", JSON.stringify(requestBody, null, 2)); } else { console.log("[onRequest] Request headers (non-JSON/non-POST):", JSON.stringify(Object.fromEntries(request.headers.entries()), null, 2)); } } catch (e) { console.error("[onRequest] Failed to parse request body as JSON:", e.message); console.log("[onRequest] Request headers (body parse error):", JSON.stringify(Object.fromEntries(request.headers.entries()), null, 2)); } if (!token) { console.error("[onRequest] Error: TELEGRAM_BOT_TOKEN environment variable is not set in this bot's Cloudflare Pages."); return new Response("TELEGRAM_BOT_TOKEN environment variable is not set.", { status: 500 }); } const url = new URL(request.url); // --- Bot Key Access Control (NEW) --- // This logic handles incoming requests from Public User Bots for validation. const botKey = request.headers.get('x-bot-key'); console.log(`[onRequest] Received X-Bot-Key: ${botKey || 'None'}`); // If a botKey is provided, validate it against BOT_USERS_DB if (botKey) { const userData = await getUserBotData(botKey, env); const now = new Date(); if (!userData || !userData.active || (userData.expires_at && new Date(userData.expires_at) < now)) { console.warn(`[onRequest] Access denied for bot key ${botKey}: Inactive, expired, or not found.`); // Return a 403 Forbidden response if the key is invalid return new Response('Access Denied: Your bot key is invalid, inactive, or has expired. Please contact the bot owner.', { status: 403 }); } console.log(`[onRequest] Bot key ${botKey} is valid and active.`); // If the request is specifically for key validation (from Public User Bot), return OK if (requestBody.type === 'validate_key' && requestBody.key === botKey) { return new Response("OK", { status: 200 }); } } // --- End Bot Key Access Control --- // --- Handle Webhook Registration/Unregistration Routes --- if (request.method === "GET" && url.pathname.endsWith("/registerWebhook")) { const pagesUrl = url.origin + url.pathname.replace("/registerWebhook", "/"); console.log(`[onRequest] Registering webhook: ${pagesUrl}`); const setWebhookApiUrl = `${TELEGRAM_API}${token}/setWebhook`; const payload = { url: pagesUrl, allowed_updates: ["message", "chat_member", "callback_query"] }; try { const response = await fetch(setWebhookApiUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); const result = await response.json(); if (response.ok && result.ok) { console.log("[onRequest] Webhook registration successful:", result); return new Response(`Webhook registered to: ${pagesUrl} (Success: ${result.ok})`, { status: 200 }); } else { console.error("[onRequest] Webhook registration failed:", result); return new Response(`Webhook registration failed: ${result.description || JSON.stringify(result)}`, { status: 500 }); } } catch (error) { console.error("[onRequest] Error during webhook registration fetch:", error); return new Response(`Error registering webhook: ${error.message}`, { status: 500 }); } } else if (request.method === "GET" && url.pathname.endsWith("/unregisterWebhook")) { const deleteWebhookApiUrl = `${TELEGRAM_API}${token}/deleteWebhook`; try { const response = await fetch(deleteWebhookApiUrl); const result = await response.json(); if (response.ok && result.ok) { console.log("[onRequest] Webhook unregistered successfully:", result); return new Response(`Webhook unregistered (Success: ${result.ok})`, { status: 200 }); } else { console.error("[onRequest] Webhook unregistration failed:", result); return new Response(`Webhook unregistration failed: ${result.description || JSON.stringify(result)}`, { status: 500 }); } } catch (error) { console.error("[onRequest] Error during webhook unregistration fetch:", error); return new Response(`Error unregistering webhook: ${error.message}`, { status: 500 }); } } // --- Main Telegram Update Handling (POST requests from Telegram) --- if (request.method === "POST") { try { const update = requestBody; if (Object.keys(update).length === 0) { console.warn("[onRequest] Received an empty or unparseable Telegram update body. Skipping processing."); return new Response("OK - Empty update received", { status: 200 }); } // Only process commands from the admin user if no botKey is present // or if the request is not a key validation request. const isWebhookControl = url.pathname.endsWith("/registerWebhook") || url.pathname.endsWith("/unregisterWebhook"); const isFromAdmin = update.message && update.message.from && update.message.from.id.toString() === adminUserId; if (!botKey && !isWebhookControl && !isFromAdmin) { console.warn("[onRequest] Access denied: No bot key provided and not an admin or webhook control request."); return new Response('Access Denied: No bot key provided. Please contact the bot owner for access.', { status: 401 }); } if (update.chat_member) { console.log("[onRequest] Handling chat_member update."); const myChatMember = update.my_chat_member; const chat = myChatMember.chat; const newChatMember = myChatMember.new_chat_member; const botInfo = await getMe(token); if (botInfo && newChatMember.status === 'member' && newChatMember.user.is_bot && newChatMember.user.id === botInfo.id) { if (chat.type === 'group' || chat.type === 'supergroup') { await sendMessage(token, chat.id, "မင်္ဂလာပါ! ကျွန်တော်က Link Checker Bot ပါ။ ဒီ Group မှာ လင့်ခ်တွေ၊ အမည်ပြောင်းလဲမှုတွေကို စစ်ဆေးပေးပါမယ်။"); } } else if (newChatMember.status === 'kicked' || newChatMember.status === 'left') { console.log(`[onRequest] Bot was removed from chat: ${chat.title || chat.id}`); } } else if (update.message) { const message = update.message; console.log(`[onRequest] Handling message update from user ${message.from.id} in chat ${message.chat.id}. Type: ${message.chat.type}`); if (message.from.id.toString() === adminUserId) { if (message.text) { console.log(`[onRequest] Admin message text: "${message.text.substring(0, 50)}..."`); const command = message.text.split(' ')[0].toLowerCase(); switch (command) { case '/start': await handleStartCommand(message, token); break; case '/generatekey': await handleGenerateKeyCommand(message, token, env); break; case '/listkeys': await handleListKeysCommand(message, token, env); break; case '/activatekey': await handleActivateKeyCommand(message, token, env); break; case '/deactivatekey': await handleDeactivateKeyCommand(message, token, env); break; case '/renewkey': await handleRenewKeyCommand(message, token, env); break; case '/setresetkey': await handleSetResetKeyCommand(message, token, env); break; case '/deletekey': await handleDeleteKeyCommand(message, token, env); break; default: await sendMessage(token, message.chat.id, "မသိသော command ဖြစ်ပါသည်။"); break; } } } else { console.log(`[onRequest] Non-admin message from user ${message.from.id}. Ignoring.`); // Optionally send a message to non-admin users, or simply ignore. // await sendMessage(token, message.chat.id, "Sorry, I only respond to my admin for now."); } } else { console.log("[onRequest] Unhandled update type:", JSON.stringify(update, null, 2)); } return new Response("OK", { status: 200 }); } catch (error) { console.error("[onRequest] Error handling Telegram webhook:", error.stack || error.message); return new Response(`Error: ${error.message}`, { status: 500 }); } } else { console.log(`[onRequest] Non-POST/non-webhook-registration request received: ${request.method} ${url.pathname}`); return new Response("This is a Telegram bot webhook endpoint. Please send POST requests or access /registerWebhook or /unregisterWebhook.", { status: 200 }); } }

**အရေးကြီး:**

၅။ Webhook မှတ်ပုံတင်ခြင်း

Control Bot ကို Telegram နှင့် ချိတ်ဆက်ရန် Webhook မှတ်ပုံတင်ရပါမည်။

  1. 1 Browser တွင် သင့်ရဲ့ Control Bot Project URL ကို /registerWebhook ဖြင့် တွဲပြီး ဝင်ပါ။ ဥပမာ:
    https://master-control.pages.dev/registerWebhook
  2. 2 "Webhook registered to: ..." စသည်ဖြင့် အောင်မြင်ကြောင်း ပြပါလိမ့်မည်။

၆။ Bot Commands များ အသုံးပြုပုံ

Control Bot ကို Telegram မှတဆင့် အောက်ပါ Commands များဖြင့် ထိန်းချုပ်နိုင်ပါသည်။

/generatekey <duration> [description]

Bot Key အသစ် ထုတ်လုပ်ရန်။ <duration> နေရာတွင် သက်တမ်းကို ထည့်ပါ။ [description] နေရာတွင် ဖော်ပြချက် ထည့်သွင်းနိုင်ပါသည်။

Duration ပုံစံများ: 10min, 1h, 1d, 3d, 1w, 1m (သို့မဟုတ်) 1month, 3m (သို့မဟုတ်) 3month, 6m (သို့မဟုတ်) 6month, 1y (သို့မဟုတ်) 1year, permanent

ဥပမာ:

/generatekey 1h Test Bot Key for Trial

ရလဒ် ဥပမာ:

✅ Bot Key အသစ် ထုတ်လုပ်ပြီးပါပြီ: 1f2ce950-d416-4c5e-b06d-e0a4d439e56a Status: Active ✅ Expires: 7/4/2025, 7:07:22 PM (Thailand) 7/4/2025, 6:37:22 PM (Myanmar) Description: Test Bot Key for Trial

/listkeys

လက်ရှိ Bot Key များစာရင်းနှင့် အခြေအနေများကို ကြည့်ရန်။

ဥပမာ:

/listkeys

ရလဒ် ဥပမာ:

Bot Keys List: Key: 1f2ce950-d416-4c5e-b06d-e0a4d439e56a Status: Active ✅ Expires: 7/4/2025, 7:07:22 PM (Thailand) 7/4/2025, 6:37:22 PM (Myanmar) Description: Test Bot Key for Trial Key: abc6d8b7-6d57-425c-9ce3-0766f51550a0 Status: Inactive ❌ Expires: 7/1/2025, 10:00:00 AM (Thailand) 7/1/2025, 9:30:00 AM (Myanmar) Description: Old Key

/activatekey <key_value>

ပိတ်ထားသော Key ကို ပြန်ဖွင့်ရန်။

ဥပမာ:

/activatekey 1f2ce950-d416-4c5e-b06d-e0a4d439e56a

/deactivatekey <key_value>

အလုပ်လုပ်နေသော Key ကို ပိတ်ရန်။

ဥပမာ:

/deactivatekey 1f2ce950-d416-4c5e-b06d-e0a4d439e56a

/renewkey <key_value> <duration>

Key သက်တမ်းကို တိုးမြှင့်ရန်။ <duration> ပုံစံများမှာ /generatekey နှင့် အတူတူပင် ဖြစ်ပါသည်။

ဥပမာ:

/renewkey 1f2ce950-d416-4c5e-b06d-e0a4d439e56a 1y

/setresetkey <key_value> <duration>

Key သက်တမ်းကို အခုအချိန်ကစပြီး ပြန်လည်သတ်မှတ်ရန်။ <duration> ပုံစံများမှာ /generatekey နှင့် အတူတူပင် ဖြစ်ပါသည်။

ဥပမာ:

/setresetkey 1f2ce950-d416-4c5e-b06d-e0a4d439e56a 3m

/deletekey <key_value>

Key ကို အပြီးတိုင် ဖျက်ရန်။

ဥပမာ:

/deletekey 1f2ce950-d416-4c5e-b06d-e0a4d439e56a