update requirements checking

This commit is contained in:
2026-01-22 15:34:50 +03:00
parent a5f6671e8b
commit 19a5942fec
4 changed files with 99 additions and 39 deletions
+2 -1
View File
@@ -4,5 +4,6 @@ export enum Requirement {
CHAT, CHAT,
CHAT_ADMIN, CHAT_ADMIN,
BOT_CHAT_ADMIN, BOT_CHAT_ADMIN,
REPLY REPLY,
SAME_USER
} }
+4
View File
@@ -34,4 +34,8 @@ export class Requirements {
isRequiresReply(): boolean { isRequiresReply(): boolean {
return this.requirements.includes(Requirement.REPLY); return this.requirements.includes(Requirement.REPLY);
} }
isRequiresSameUser(): boolean {
return this.requirements.includes(Requirement.SAME_USER);
}
} }
+5 -1
View File
@@ -1,10 +1,12 @@
import {CallbackCommand} from "../base/callback-command"; import {CallbackCommand} from "../base/callback-command";
import {CallbackQuery} from "typescript-telegram-bot-api"; import {CallbackQuery} from "typescript-telegram-bot-api";
import {abortOllamaRequest, bot, getOllamaRequest} from "../index"; import {abortOllamaRequest, bot, getOllamaRequest} from "../index";
import {Environment} from "../common/environment";
import {logError} from "../util/utils"; import {logError} from "../util/utils";
import {MessageStore} from "../common/message-store"; import {MessageStore} from "../common/message-store";
import {StoredMessage} from "../model/stored-message"; import {StoredMessage} from "../model/stored-message";
import {Requirements} from "../base/requirements";
import {Requirement} from "../base/requirement";
import {Environment} from "../common/environment";
const cancelledText = "```Ollama\n❌ Отменено```"; const cancelledText = "```Ollama\n❌ Отменено```";
@@ -13,6 +15,8 @@ export class OllamaCancel extends CallbackCommand {
data = "/cancel_ollama"; data = "/cancel_ollama";
text = "Cancel Ollama generation"; text = "Cancel Ollama generation";
requirements = Requirements.Build(Requirement.SAME_USER);
async execute(query: CallbackQuery): Promise<void> { async execute(query: CallbackQuery): Promise<void> {
const chatId = query.message.chat.id; const chatId = query.message.chat.id;
const fromId = query.from.id; const fromId = query.from.id;
+88 -37
View File
@@ -1,7 +1,15 @@
import * as si from "systeminformation"; import * as si from "systeminformation";
import {ChatCommand} from "../base/chat-command"; import {ChatCommand} from "../base/chat-command";
import {CallbackCommand} from "../base/callback-command"; import {CallbackCommand} from "../base/callback-command";
import {CallbackQuery, InlineKeyboardMarkup, Message, ParseMode, PhotoSize, User} from "typescript-telegram-bot-api"; import {
CallbackQuery,
ChatMember,
InlineKeyboardMarkup,
Message,
ParseMode,
PhotoSize,
User
} from "typescript-telegram-bot-api";
import {Environment} from "../common/environment"; import {Environment} from "../common/environment";
import {TelegramError} from "typescript-telegram-bot-api/dist/errors"; import {TelegramError} from "typescript-telegram-bot-api/dist/errors";
import {bot, botUser, messageDao, setSystemInfo} from "../index"; import {bot, botUser, messageDao, setSystemInfo} from "../index";
@@ -15,6 +23,7 @@ import * as orm from "drizzle-orm";
import {sql, type SQL} from "drizzle-orm"; import {sql, type SQL} from "drizzle-orm";
import fs from "node:fs"; import fs from "node:fs";
import path from "node:path"; import path from "node:path";
import {MessageStore} from "../common/message-store";
export const ignore = () => { export const ignore = () => {
}; };
@@ -71,70 +80,116 @@ export function searchCallbackCommand(commands: CallbackCommand[], data: string)
return null; return null;
} }
export async function checkRequirements(cmd: ChatCommand | null, msg: Message): Promise<boolean> { export async function checkRequirements(cmd: ChatCommand | CallbackCommand | null, msg?: Message, cb?: CallbackQuery): Promise<boolean> {
if (!cmd) return false; if (!cmd) return false;
if (!msg && !cb) return false;
if (Environment.ONLY_FOR_CREATOR_MODE && msg.from.id !== Environment.CREATOR_ID) return false; const isChatCommand = "title" in cmd;
const isCallbackCommand = "data" in cmd;
let title: string;
const fromId = msg.from?.id || -1; if (isChatCommand) {
title = cmd.title;
} else if (isCallbackCommand) {
title = cmd.data;
} else {
return false;
}
const cbId = cb?.id;
const chatId = msg?.chat?.id || cb?.message?.chat?.id || -1;
const messageId = msg?.message_id || cb?.message?.message_id || -1;
const fromId = msg?.from?.id || cb?.from?.id || -1;
const chatType = msg?.chat?.type || cb?.message?.chat?.type || null;
if (chatId === -1 || messageId === -1 || fromId === -1 || !chatType) return false;
if (Environment.ONLY_FOR_CREATOR_MODE && fromId !== Environment.CREATOR_ID) return false;
if (Environment.CHAT_IDS_WHITELIST.size > 0 && if (Environment.CHAT_IDS_WHITELIST.size > 0 &&
!Environment.CHAT_IDS_WHITELIST.has(msg.chat.id) && !Environment.CHAT_IDS_WHITELIST.has(chatId) &&
!Environment.ADMIN_IDS.has(msg.chat.id) && !Environment.ADMIN_IDS.has(chatId) &&
!Environment.ADMIN_IDS.has(msg.from.id)) { !Environment.ADMIN_IDS.has(fromId)) {
console.log(`${cmd.title}: chatId whitelist ignored.`); console.log(`${title}: chatId whitelist ignored.`);
return false; return false;
} }
const reqs = cmd.requirements; const reqs = cmd.requirements;
if (!reqs) return true; if (!reqs) return true;
const notifyUser = async (text: string) => {
if (msg) {
await replyToMessage({chat_id: chatId, message_id: messageId, text: text});
} else if (cb) {
await bot.answerCallbackQuery({
callback_query_id: cbId,
text: text,
cache_time: 0,
show_alert: true
}).catch(logError);
}
};
if (reqs.isRequiresBotCreator() && fromId !== Environment.CREATOR_ID) { if (reqs.isRequiresBotCreator() && fromId !== Environment.CREATOR_ID) {
console.log(`${cmd.title}: creatorId is bad`); console.log(`${title}: creatorId is bad`);
await oldReplyToMessage(msg, "Вы не являетесь создателем бота."); await notifyUser("Вы не являетесь создателем бота.");
return false; return false;
} }
if (reqs.isRequiresBotAdmin() && !Environment.ADMIN_IDS.has(fromId)) { if (reqs.isRequiresBotAdmin() && !Environment.ADMIN_IDS.has(fromId)) {
console.log(`${cmd.title}: adminId is bad`); console.log(`${title}: adminId is bad`);
await oldReplyToMessage(msg, "Вы не являетесь администратором бота."); await notifyUser("Вы не являетесь администратором бота.");
return false; return false;
} }
if (reqs.isRequiresChat() && msg.chat.type === "private") { if (reqs.isRequiresChat() && msg.chat.type === "private") {
console.log(`${cmd.title}: chatId is bad`); console.log(`${title}: chatId is bad`);
await oldReplyToMessage(msg, "Тут Вам не чат."); await notifyUser("Тут Вам не чат.");
return false; return false;
} }
if (reqs.isRequiresChatAdmin()) { if (reqs.isRequiresChatAdmin()) {
const member = await bot.getChatMember({chat_id: msg.chat.id, user_id: msg.from.id}); const member = await bot.getChatMember({chat_id: chatId, user_id: fromId});
const isAdmin = member.status === "administrator" || member.status === "creator";
if (!isAdmin) { if (!isMemberAdmin(member)) {
console.log(`${cmd.title}: chatAdminId is bad`); console.log(`${title}: chatAdminId is bad`);
await oldReplyToMessage(msg, "Вы не являетесь администратором чата."); await notifyUser("Вы не являетесь администратором чата.");
return false; return false;
} }
} }
if (reqs.isRequiresBotChatAdmin() && msg.chat.type !== "private") { if (reqs.isRequiresBotChatAdmin() && chatType !== "private") {
const member = await bot.getChatMember({chat_id: msg.chat.id, user_id: botUser.id}); const member = await bot.getChatMember({chat_id: chatId, user_id: botUser.id});
const isAdmin = member.status === "administrator" || member.status === "creator";
if (!isAdmin) { if (!isMemberAdmin(member)) {
console.log(`${cmd.title}: botChatAdminId is bad`); console.log(`${title}: botChatAdminId is bad`);
await oldReplyToMessage(msg, "Бот не является администратором чата."); await notifyUser("Бот не является администратором чата.");
return false; return false;
} }
} }
if (reqs.isRequiresReply() && !msg.reply_to_message) { if (reqs.isRequiresReply() && !msg?.reply_to_message) {
console.log(`${cmd.title}: replyMessage is bad`); console.log(`${title}: replyMessage is bad`);
await oldReplyToMessage(msg, "Отсутствует ответ на сообщение."); await notifyUser("Отсутствует ответ на сообщение.");
return false; return false;
} }
if (reqs.isRequiresSameUser()) {
let originalFromId: number | null;
try {
originalFromId = (await MessageStore.get(chatId, messageId))?.fromId;
} catch (e) {
logError(e);
originalFromId = null;
}
if (originalFromId && fromId !== originalFromId && fromId !== Environment.CREATOR_ID) {
console.log(`${title}: sameUser is bad`);
await notifyUser("Только автор оригинального сообщения может выполнить это действие.");
return false;
}
}
return true; return true;
} }
@@ -148,20 +203,12 @@ export async function executeChatCommand(cmd: ChatCommand | null, msg: Message,
} }
export async function findAndExecuteCallbackCommand(commands: CallbackCommand[], query: CallbackQuery): Promise<boolean> { export async function findAndExecuteCallbackCommand(commands: CallbackCommand[], query: CallbackQuery): Promise<boolean> {
const fromId = query.from.id;
const data = query.data || ""; const data = query.data || "";
const cmd = searchCallbackCommand(commands, data); const cmd = searchCallbackCommand(commands, data);
if (!cmd) return false; if (!cmd) return false;
// TODO: 15/01/2026, Danil Nikolaev: reimplement if (!await checkRequirements(cmd, null, query)) return false;
const requirements = cmd.requirements;
if (requirements) {
if (requirements.isRequiresBotAdmin() && !Environment.ADMIN_IDS.has(fromId)) {
console.log(`${cmd.data}: adminId is bad: ${fromId}`);
return false;
}
}
await cmd.execute(query); await cmd.execute(query);
await cmd.answerCallbackQuery(query); await cmd.answerCallbackQuery(query);
@@ -312,6 +359,10 @@ export function fullName(from: User): string {
return fullName; return fullName;
} }
export function isMemberAdmin(member: ChatMember): boolean {
return member.status === "administrator" || member.status === "creator";
}
export function getUptime(): string { export function getUptime(): string {
const processUptime = Math.ceil(process.uptime()); const processUptime = Math.ceil(process.uptime());