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_ADMIN,
BOT_CHAT_ADMIN,
REPLY
REPLY,
SAME_USER
}
+4
View File
@@ -34,4 +34,8 @@ export class Requirements {
isRequiresReply(): boolean {
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 {CallbackQuery} from "typescript-telegram-bot-api";
import {abortOllamaRequest, bot, getOllamaRequest} from "../index";
import {Environment} from "../common/environment";
import {logError} from "../util/utils";
import {MessageStore} from "../common/message-store";
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❌ Отменено```";
@@ -13,6 +15,8 @@ export class OllamaCancel extends CallbackCommand {
data = "/cancel_ollama";
text = "Cancel Ollama generation";
requirements = Requirements.Build(Requirement.SAME_USER);
async execute(query: CallbackQuery): Promise<void> {
const chatId = query.message.chat.id;
const fromId = query.from.id;
+88 -37
View File
@@ -1,7 +1,15 @@
import * as si from "systeminformation";
import {ChatCommand} from "../base/chat-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 {TelegramError} from "typescript-telegram-bot-api/dist/errors";
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 fs from "node:fs";
import path from "node:path";
import {MessageStore} from "../common/message-store";
export const ignore = () => {
};
@@ -71,70 +80,116 @@ export function searchCallbackCommand(commands: CallbackCommand[], data: string)
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 (!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 &&
!Environment.CHAT_IDS_WHITELIST.has(msg.chat.id) &&
!Environment.ADMIN_IDS.has(msg.chat.id) &&
!Environment.ADMIN_IDS.has(msg.from.id)) {
console.log(`${cmd.title}: chatId whitelist ignored.`);
!Environment.CHAT_IDS_WHITELIST.has(chatId) &&
!Environment.ADMIN_IDS.has(chatId) &&
!Environment.ADMIN_IDS.has(fromId)) {
console.log(`${title}: chatId whitelist ignored.`);
return false;
}
const reqs = cmd.requirements;
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) {
console.log(`${cmd.title}: creatorId is bad`);
await oldReplyToMessage(msg, "Вы не являетесь создателем бота.");
console.log(`${title}: creatorId is bad`);
await notifyUser("Вы не являетесь создателем бота.");
return false;
}
if (reqs.isRequiresBotAdmin() && !Environment.ADMIN_IDS.has(fromId)) {
console.log(`${cmd.title}: adminId is bad`);
await oldReplyToMessage(msg, "Вы не являетесь администратором бота.");
console.log(`${title}: adminId is bad`);
await notifyUser("Вы не являетесь администратором бота.");
return false;
}
if (reqs.isRequiresChat() && msg.chat.type === "private") {
console.log(`${cmd.title}: chatId is bad`);
await oldReplyToMessage(msg, "Тут Вам не чат.");
console.log(`${title}: chatId is bad`);
await notifyUser("Тут Вам не чат.");
return false;
}
if (reqs.isRequiresChatAdmin()) {
const member = await bot.getChatMember({chat_id: msg.chat.id, user_id: msg.from.id});
const isAdmin = member.status === "administrator" || member.status === "creator";
const member = await bot.getChatMember({chat_id: chatId, user_id: fromId});
if (!isAdmin) {
console.log(`${cmd.title}: chatAdminId is bad`);
await oldReplyToMessage(msg, "Вы не являетесь администратором чата.");
if (!isMemberAdmin(member)) {
console.log(`${title}: chatAdminId is bad`);
await notifyUser("Вы не являетесь администратором чата.");
return false;
}
}
if (reqs.isRequiresBotChatAdmin() && msg.chat.type !== "private") {
const member = await bot.getChatMember({chat_id: msg.chat.id, user_id: botUser.id});
const isAdmin = member.status === "administrator" || member.status === "creator";
if (reqs.isRequiresBotChatAdmin() && chatType !== "private") {
const member = await bot.getChatMember({chat_id: chatId, user_id: botUser.id});
if (!isAdmin) {
console.log(`${cmd.title}: botChatAdminId is bad`);
await oldReplyToMessage(msg, "Бот не является администратором чата.");
if (!isMemberAdmin(member)) {
console.log(`${title}: botChatAdminId is bad`);
await notifyUser("Бот не является администратором чата.");
return false;
}
}
if (reqs.isRequiresReply() && !msg.reply_to_message) {
console.log(`${cmd.title}: replyMessage is bad`);
await oldReplyToMessage(msg, "Отсутствует ответ на сообщение.");
if (reqs.isRequiresReply() && !msg?.reply_to_message) {
console.log(`${title}: replyMessage is bad`);
await notifyUser("Отсутствует ответ на сообщение.");
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;
}
@@ -148,20 +203,12 @@ export async function executeChatCommand(cmd: ChatCommand | null, msg: Message,
}
export async function findAndExecuteCallbackCommand(commands: CallbackCommand[], query: CallbackQuery): Promise<boolean> {
const fromId = query.from.id;
const data = query.data || "";
const cmd = searchCallbackCommand(commands, data);
if (!cmd) return false;
// TODO: 15/01/2026, Danil Nikolaev: reimplement
const requirements = cmd.requirements;
if (requirements) {
if (requirements.isRequiresBotAdmin() && !Environment.ADMIN_IDS.has(fromId)) {
console.log(`${cmd.data}: adminId is bad: ${fromId}`);
return false;
}
}
if (!await checkRequirements(cmd, null, query)) return false;
await cmd.execute(query);
await cmd.answerCallbackQuery(query);
@@ -312,6 +359,10 @@ export function fullName(from: User): string {
return fullName;
}
export function isMemberAdmin(member: ChatMember): boolean {
return member.status === "administrator" || member.status === "creator";
}
export function getUptime(): string {
const processUptime = Math.ceil(process.uptime());