Telegram Bot Setup Guide
Master Control Bot အတွက် Telegram Bot Token ကို @BotFather မှ ရယူရပါမည်။
/start command ပို့ပါ။
/newbot command ကို ပို့ပြီး Bot အသစ်တစ်ခု ဖန်တီးပါ။
LicenseMasterBot) ပေးပါ။
LicenseMaster_bot) ပေးပါ။ Username သည် _bot ဖြင့် ဆုံးရပါမည်။
123456789:ABCDE-FGHIJ-KLMNO-PQRST-UVWXY
Master Control Bot အတွက် Cloudflare Pages Project အသစ်တစ်ခု တည်ဆောက်ပါ။
master-control)
Project Setup အဆင့်တွင် Build settings အောက်ရှိ Environment Variables များတွင် အောက်ပါ Variables များကို ထည့်သွင်းပေးရပါမည်။
TELEGRAM_BOT_TOKEN
TELEGRAM_BOT_TOKEN
123456789:ABCDE-FGHIJ-KLMNO-PQRST-UVWXY)
BOT_USERS_DB
BOT_USERS_DB
bot_users_data ဟု ပေးပါ။ Save/Add နှိပ်ပါ။
ADMIN_USER_ID
ADMIN_USER_ID
7576434717)
သင့်ရဲ့ 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 });
}
}
**အရေးကြီး:**
Control Bot ကို Telegram နှင့် ချိတ်ဆက်ရန် Webhook မှတ်ပုံတင်ရပါမည်။
/registerWebhook ဖြင့် တွဲပြီး ဝင်ပါ။ ဥပမာ:
https://master-control.pages.dev/registerWebhook
Control Bot ကို Telegram မှတဆင့် အောက်ပါ Commands များဖြင့် ထိန်းချုပ်နိုင်ပါသည်။
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
လက်ရှိ 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
ပိတ်ထားသော Key ကို ပြန်ဖွင့်ရန်။
ဥပမာ:
/activatekey 1f2ce950-d416-4c5e-b06d-e0a4d439e56a
အလုပ်လုပ်နေသော Key ကို ပိတ်ရန်။
ဥပမာ:
/deactivatekey 1f2ce950-d416-4c5e-b06d-e0a4d439e56a
Key သက်တမ်းကို တိုးမြှင့်ရန်။ <duration> ပုံစံများမှာ /generatekey နှင့် အတူတူပင် ဖြစ်ပါသည်။
ဥပမာ:
/renewkey 1f2ce950-d416-4c5e-b06d-e0a4d439e56a 1y
Key သက်တမ်းကို အခုအချိန်ကစပြီး ပြန်လည်သတ်မှတ်ရန်။ <duration> ပုံစံများမှာ /generatekey နှင့် အတူတူပင် ဖြစ်ပါသည်။
ဥပမာ:
/setresetkey 1f2ce950-d416-4c5e-b06d-e0a4d439e56a 3m
Key ကို အပြီးတိုင် ဖျက်ရန်။
ဥပမာ:
/deletekey 1f2ce950-d416-4c5e-b06d-e0a4d439e56a