Update bot version and enhance user checks

Updated the bot version and modified the local question bank. Added mandatory username check for private messages and adjusted the /info command to remove full name display.
This commit is contained in:
Vaghr
2026-01-05 16:54:55 +08:00
committed by GitHub
parent 8b6bbb4128
commit 2ea97b879f

View File

@@ -1,9 +1,6 @@
// Cloudflare WorkerTelegram 双向机器人 (纯本地极速版 v4.2)
// 修改内容:
// 1. 私聊逻辑增加 Username 强制检查,未设置则拦截。
// 2. /info 指令增加显示用户的完整姓名 (Full Name)。
// Cloudflare WorkerTelegram 双向机器人 (纯本地极速版 v4.0)
// --- 1. 本地题库配置 (14条) ---
// --- 本地题库 (15条) ---
const LOCAL_QUESTIONS = [
{"question": "冰融化后会变成什么?", "correct_answer": "水", "incorrect_answers": ["石头", "木头", "火"]},
{"question": "正常人有几只眼睛?", "correct_answer": "2", "incorrect_answers": ["1", "3", "4"]},
@@ -18,12 +15,13 @@ const LOCAL_QUESTIONS = [
{"question": "鱼通常生活在哪里?", "correct_answer": "水里", "incorrect_answers": ["树上", "土里", "火里"]},
{"question": "我们用什么器官来听声音?", "correct_answer": "耳朵", "incorrect_answers": ["眼睛", "鼻子", "嘴巴"]},
{"question": "晴朗的天空通常是什么颜色的?", "correct_answer": "蓝色", "incorrect_answers": ["绿色", "红色", "紫色"]},
{"question": "太阳从哪个方向升起?", "correct_answer": "东方", "incorrect_answers": ["西方", "南方", "北方"]},
{"question": "小狗发出的叫声通常是?", "correct_answer": "汪汪", "incorrect_answers": ["喵喵", "咩咩", "呱呱"]}
];
export default {
async fetch(request, env, ctx) {
// --- 2. 环境自检 ---
// 环境自检
if (!env.TOPIC_MAP) return new Response("Error: KV 'TOPIC_MAP' not bound.");
if (!env.BOT_TOKEN) return new Response("Error: BOT_TOKEN not set.");
if (!env.SUPERGROUP_ID) return new Response("Error: SUPERGROUP_ID not set.");
@@ -37,9 +35,6 @@ export default {
return new Response("OK");
}
// --- 3. 路由分发 ---
// A. 处理按钮回调
if (update.callback_query) {
await handleCallbackQuery(update.callback_query, env, ctx);
return new Response("OK");
@@ -50,7 +45,6 @@ export default {
ctx.waitUntil(flushExpiredMediaGroups(env, Date.now()));
// B. 处理私聊消息
if (msg.chat && msg.chat.type === "private") {
try {
await handlePrivateMessage(msg, env, ctx);
@@ -62,7 +56,6 @@ export default {
return new Response("OK");
}
// C. 处理群组消息
const supergroupId = Number(env.SUPERGROUP_ID);
if (msg.chat && Number(msg.chat.id) === supergroupId) {
if (msg.forum_topic_closed && msg.message_thread_id) {
@@ -89,27 +82,14 @@ async function handlePrivateMessage(msg, env, ctx) {
const userId = msg.chat.id;
const key = `user:${userId}`;
// 1. 过滤掉非 /start 的指令
// 拦截普通用户发送的指令
if (msg.text && msg.text.startsWith("/") && msg.text.trim() !== "/start") {
return;
}
// 2. 检查黑名单
const isBanned = await env.TOPIC_MAP.get(`banned:${userId}`);
if (isBanned) return;
// [新增] 2.1 强制检查 Username 是否存在
// 如果 msg.from.username 为空或 undefined直接中断并提示
if (!msg.from.username) {
await tgCall(env, "sendMessage", {
chat_id: userId,
text: "⚠️ **很抱歉,你的用户名(username)未设置,无法进行人机验证流程!消息发送失败!**\n\n(请在 Telegram 设置中配置用户名后重试)",
parse_mode: "Markdown"
});
return;
}
// 3. 检查验证状态
const verified = await env.TOPIC_MAP.get(`verified:${userId}`);
if (!verified) {
@@ -119,7 +99,6 @@ async function handlePrivateMessage(msg, env, ctx) {
return;
}
// 4. 已验证用户,转发消息
await forwardToTopic(msg, userId, key, env, ctx);
}
@@ -180,6 +159,7 @@ async function handleAdminReply(msg, env, ctx) {
const threadId = msg.message_thread_id;
const text = (msg.text || "").trim();
// 反查 UserId
let userId = null;
const list = await env.TOPIC_MAP.list({ prefix: "user:" });
for (const { name } of list.keys) {
@@ -190,9 +170,10 @@ async function handleAdminReply(msg, env, ctx) {
}
}
// 如果找不到用户,说明可能是在普通话题,或者数据丢失,直接返回
if (!userId) return;
// --- 管理员指令区域 ---
// --- 指令区域 ---
if (text === "/close") {
const key = `user:${userId}`;
@@ -242,23 +223,13 @@ async function handleAdminReply(msg, env, ctx) {
return;
}
// [修改] /info 指令逻辑:增加显示 Full Name
if (text === "/info") {
const chatInfo = await tgCall(env, "getChat", { chat_id: userId });
const r = chatInfo.result || {};
// 1. 获取 Username
const username = r.username ? `@${r.username}` : "未设置";
// 2. [新增] 获取 Full Name (First + Last)
const fullName = (r.first_name + " " + (r.last_name || "")).trim();
const info = `👤 **用户信息**\nUID: \`${userId}\`\nName: \`${fullName}\`\nUsername: \`${username}\`\nTopic ID: \`${threadId}\`\nLink: [点击私聊](tg://user?id=${userId})`;
const info = `👤 **用户信息**\nUID: \`${userId}\`\nTopic ID: \`${threadId}\`\nLink: [点击私聊](tg://user?id=${userId})`;
await tgCall(env, "sendMessage", { chat_id: env.SUPERGROUP_ID, message_thread_id: threadId, text: info, parse_mode: "Markdown" });
return;
}
// 转发管理员消息给用户
if (msg.media_group_id) {
await handleMediaGroup(msg, env, ctx, { direction: "t2p", targetChat: userId, threadId: null });
return;
@@ -266,9 +237,10 @@ async function handleAdminReply(msg, env, ctx) {
await tgCall(env, "copyMessage", { chat_id: userId, from_chat_id: env.SUPERGROUP_ID, message_id: msg.message_id });
}
// ---------------- 验证模块 ----------------
// ---------------- 验证模块 (纯本地) ----------------
async function sendVerificationChallenge(userId, env, pendingMsgId) {
// 直接从本地题库随机
const q = LOCAL_QUESTIONS[Math.floor(Math.random() * LOCAL_QUESTIONS.length)];
const challenge = {
question: q.question,
@@ -276,7 +248,9 @@ async function sendVerificationChallenge(userId, env, pendingMsgId) {
options: shuffleArray([...q.incorrect_answers, q.correct_answer])
};
// 使用 8 位短 ID 防止按钮失效
const verifyId = Math.random().toString(36).substring(2, 10);
const state = { ans: challenge.correct, pending: pendingMsgId };
await env.TOPIC_MAP.put(`chal:${verifyId}`, JSON.stringify(state), { expirationTtl: 300 });
@@ -325,6 +299,7 @@ async function handleCallbackQuery(query, env, ctx) {
if (userAns === state.ans) {
await tgCall(env, "answerCallbackQuery", { callback_query_id: query.id, text: "✅ 验证通过" });
// 30天有效期
await env.TOPIC_MAP.put(`verified:${userId}`, "1", { expirationTtl: 2592000 });
await env.TOPIC_MAP.delete(`chal:${verifyId}`);