1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
| const TOKEN = ENV_BOT_TOKEN; const WEBHOOK = '/endpoint'; const SECRET = ENV_BOT_SECRET; const ADMIN_UID = ENV_ADMIN_UID; const VERIFICATION_TTL = 60 * 60 * 24 * 30; const CF_TURNSTILE_SITE_KEY = ENV_CF_SITE_KEY; const CF_TURNSTILE_SECRET_KEY = ENV_CF_SECRET_KEY;
function apiUrl(methodName, params = null) { let query = ''; if (params) { query = '?' + new URLSearchParams(params).toString(); } return `https://api.telegram.org/bot${TOKEN}/${methodName}${query}`; }
function requestTelegram(methodName, body, params = null) { return fetch(apiUrl(methodName, params), { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) }).then(r => r.json()); }
function sendMessage(msg = {}) { return requestTelegram('sendMessage', msg); }
function copyMessage(msg = {}) { return requestTelegram('copyMessage', msg); }
function forwardMessage(msg) { return requestTelegram('forwardMessage', msg); }
addEventListener('fetch', event => { const url = new URL(event.request.url); if (url.pathname === WEBHOOK) { event.respondWith(handleWebhook(event, url)); } else if (url.pathname === '/registerWebhook') { event.respondWith(registerWebhook(event, url, WEBHOOK, SECRET)); } else if (url.pathname === '/verify') { event.respondWith(handleVerifyPage(event.request)); } else if (url.pathname === '/verify-callback') { event.respondWith(handleVerifyCallback(event.request)); } else { event.respondWith(new Response('No handler for this request')); } });
async function handleWebhook(event, url) { if (event.request.headers.get('X-Telegram-Bot-Api-Secret-Token') !== SECRET) { return new Response('Unauthorized', { status: 403 }); } const update = await event.request.json(); event.waitUntil(onUpdate(update, url.origin)); return new Response('Ok'); }
async function onUpdate(update, origin) { if ('message' in update) { await onMessage(update.message, origin); } }
async function onMessage(message, origin) { const chatId = message.chat.id.toString(); if (chatId === ADMIN_UID) { return handleAdminMessage(message); } else { const isBlocked = await nfd.get('blocked-' + chatId); if (isBlocked) { return sendMessage({ chat_id: chatId, text: '🚫 您已被管理员拉黑。' }); } const isVerified = await nfd.get('verified-' + chatId); if (isVerified) { return handleGuestMessage(message); } else { return handleVerification(message, chatId, origin); } } }
async function handleAdminMessage(message) { const text = (message.text || '').trim(); const reply = message.reply_to_message; if (text === '/block') { if (reply) { const guestId = await nfd.get('msg-map-' + reply.message_id); if (guestId) { await nfd.put('blocked-' + guestId, 'true'); return sendMessage({ chat_id: ADMIN_UID, text: `🚫 用户 ${guestId} 已被拉黑。` }); } } return sendMessage({ chat_id: ADMIN_UID, text: '⚠️ 请回复一条转发的消息进行拉黑。' }); } if (reply) { const guestId = await nfd.get('msg-map-' + reply.message_id); if (guestId) { return copyMessage({ chat_id: guestId, from_chat_id: message.chat.id, message_id: message.message_id, }); } } return sendMessage({ chat_id: ADMIN_UID, text: '🤖 管理面板:回复消息即发送,发送 /block 拉黑。' }); }
async function handleVerification(message, chatId, origin) { const verifyUrl = `${origin}/verify?uid=${chatId}`; return sendMessage({ chat_id: chatId, text: '🛡 为了防止垃圾消息,请点击按钮完成验证:', reply_markup: { inline_keyboard: [[{ text: '🤖 开始人机验证', web_app: { url: verifyUrl } }]] } }); }
function handleVerifyPage(request) { const html = `<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>验证</title><script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script><script src="https://telegram.org/js/telegram-web-app.js"></script><style>body { font-family: sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; margin: 0; background: #f0f2f5; }.card { background: white; padding: 2rem; border-radius: 12px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); text-align: center; }</style></head><body><div class="card"><h2>人机验证</h2><div class="cf-turnstile" data-sitekey="${CF_TURNSTILE_SITE_KEY}" data-callback="onVerify"></div><p id="status"></p></div><script>const tg = window.Telegram.WebApp; tg.ready(); function onVerify(token) { const uid = new URLSearchParams(window.location.search).get('uid'); fetch('/verify-callback', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token, uid }) }).then(res => { if (res.ok) { document.getElementById('status').innerText = "✅ 验证成功!"; setTimeout(() => tg.close(), 1500); } }); }</script></body></html>`; return new Response(html, { headers: { 'content-type': 'text/html;charset=UTF-8' } }); }
async function handleVerifyCallback(request) { const { token, uid } = await request.json(); const formData = new FormData(); formData.append('secret', CF_TURNSTILE_SECRET_KEY); formData.append('response', token); const result = await fetch('[https://challenges.cloudflare.com/turnstile/v0/siteverify](https://challenges.cloudflare.com/turnstile/v0/siteverify)', { method: 'POST', body: formData }).then(r => r.json()); if (result.success) { await nfd.put('verified-' + uid, 'true', { expirationTtl: VERIFICATION_TTL }); await sendMessage({ chat_id: uid, text: '✅ 验证通过!现在您可以发送消息了。' }); return new Response('ok'); } return new Response('fail', { status: 400 }); }
async function handleGuestMessage(message) { const forwardReq = await forwardMessage({ chat_id: ADMIN_UID, from_chat_id: message.chat.id, message_id: message.message_id }); if (forwardReq.ok) { await nfd.put('msg-map-' + forwardReq.result.message_id, message.chat.id.toString(), { expirationTtl: 172800 }); } }
async function registerWebhook(event, requestUrl, suffix, secret) { const webhookUrl = `${requestUrl.protocol}//${requestUrl.hostname}${suffix}`; const r = await (await fetch(apiUrl('setWebhook', { url: webhookUrl, secret_token: secret }))).json(); return new Response(JSON.stringify(r)); }
|