Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

Помощь с sysban.js

Мар
151
43
Пользователь
Привет помогитие мне реализовать sysban пытаюсь сделать чтобы при забаненных пользователей он исключал и писал сообщение, я пытаюсь делаю но не получается вот код
И да результа 0 тупо кикает 2 раза и все и человека можно добавить

Код:
const database = require('../databases.js');
const { checkSysAccess, getAccessLevelName } = require('./sysadmin.js');
const { hasCommandAccess, getAccessDeniedMessage } = require('../utils/commandAccess.js');
const { extractNumericId } = require('../utils/userUtils.js');
const vk = require('../vkInstance.js');
const util = require('util');
const fs = require('fs');
const path = require('path');
const databaseQuery = util.promisify(database.query);
const SYSBANNED_FILE = path.join(__dirname, '../data/sysbanned.json');
// Хранилище для отслеживания частоты использования команды
const commandUsage = new Map();
// Кэш забаненных пользователей для быстрой проверки
const bannedUsersCache = new Map();
const CACHE_UPDATE_INTERVAL = 60000; // Обновление кэша каждую минуту
// Функция обновления кэша забаненных пользователей
async function updateBannedUsersCache() {
  try {
    const now = Math.floor(Date.now() / 1000);
    const query = 'SELECT userid, time, level FROM sysbanned WHERE level = 2 AND (time = 0 OR time > ?)';
    const results = await databaseQuery(query, [now]);
  
    bannedUsersCache.clear();
    results.forEach(row => {
      bannedUsersCache.set(Number(row.userid), {
        level: row.level,
        time: row.time
      });
    });
  
    console.log(`[SYSBAN] Кэш забаненных обновлен: ${bannedUsersCache.size} пользователей`);
  } catch (error) {
    console.error('[SYSBAN] Ошибка обновления кэша:', error);
  }
}
// Обновляем кэш при старте и каждую минуту
updateBannedUsersCache();
setInterval(updateBannedUsersCache, CACHE_UPDATE_INTERVAL);
function isLevel2Banned(userId) {
  if (!fs.existsSync(SYSBANNED_FILE)) return false;
  const data = JSON.parse(fs.readFileSync(SYSBANNED_FILE, 'utf-8'));
  const now = Math.floor(Date.now() / 1000);
  const ban = data.find(u => u.userid === userId && u.level === 2 && (u.time === 0 || u.time > now));
  return !!ban;
}
// Функция для проверки лимита использования команды
function checkCommandLimit(userId) {
  const now = Date.now();
  const userUsage = commandUsage.get(userId) || { count: 0, lastReset: now, blockedUntil: 0 };
 
  // Проверяем, не заблокирован ли пользователь
  if (userUsage.blockedUntil > now) {
    const minutesLeft = Math.ceil((userUsage.blockedUntil - now) / 60000);
    return {
      allowed: false,
      message: `❌ Превышен лимит использования команды. Попробуйте через ${minutesLeft} мин.`
    };
  }
 
  // Сбрасываем счетчик, если прошло больше 10 минут с последнего сброса
  if (now - userUsage.lastReset > 600000) { // 10 минут в миллисекундах
    userUsage.count = 0;
    userUsage.lastReset = now;
  }
 
  // Увеличиваем счетчик
  userUsage.count++;
 
  // Если использовано 3 раза подряд, блокируем на 10 минут
  if (userUsage.count >= 3) {
    userUsage.blockedUntil = now + 600000; // 10 минут
    userUsage.count = 0;
    commandUsage.set(userId, userUsage);
    return {
      allowed: false,
      message: '❌ Превышен лимит использования команды. Команда заблокирована на 10 минут.'
    };
  }
 
  commandUsage.set(userId, userUsage);
  return { allowed: true };
}
// Улучшенная функция для кика пользователя из всех бесед
async function kickUserFromAllChats(userId) {
  try {
    let kickedCount = 0;
    const errors = [];
    const kickPromises = [];
    let offset = 0;
    const pageSize = 200;
    for (;;) {
      const conversations = await vk.api.messages.getConversations({
        count: pageSize,
        offset,
        extended: 1
      });
      const items = conversations.items || [];
      if (!items.length) break;
      for (const item of items) {
        const peerId = item.conversation.peer.id;
        if (peerId <= 2000000000) continue;
        if (item.conversation.chat_settings?.state === 'disabled') continue;
        const chatId = peerId - 2000000000;
        const kickPromise = vk.api.messages.removeChatUser({
          chat_id: chatId,
          member_id: userId
        })
          .then(() => {
            kickedCount++;
            console.log(
              `[SYSBAN] Пользователь ${userId} кикнут из беседы ${peerId}`
            );
          })
          .catch(error => {
            if (
              error.code === 945 ||
              error.message?.includes('Chat was disabled')
            ) {
              return;
            }
            if (
              error.code === 935 ||
              error.message?.includes('User not in chat')
            ) {
              return;
            }
            const errorMsg =
              `Ошибка при кике из беседы ${peerId}: ${error.message}`;
            console.error(`[SYSBAN] ${errorMsg}`);
            errors.push(errorMsg);
          });
        kickPromises.push(kickPromise);
      }
      offset += items.length;
      if (items.length < pageSize) break;
    }
    await Promise.allSettled(kickPromises);
    return { kickedCount, errors };
  } catch (error) {
    console.error('[SYSBAN] Ошибка при кике пользователя из всех бесед:', error);
    return { kickedCount: 0, errors: [error.message] };
  }
}
// Функция для автоматического кика при попытке добавить в беседу
async function setupAutoKick() {
  try {
    // Слушаем новые сообщения о добавлении в беседу
    const eventHandler = async (event) => {
      if (event.type === 'message_new') {
        const message = event.object.message;
      
        // Проверяем, что это действие с беседой
        if (message.action && message.action.type === 'chat_invite_user') {
          const invitedUserId = message.action.member_id;
        
          // Быстрая проверка по кэшу
          if (bannedUsersCache.has(invitedUserId)) {
            console.log(`[SYSBAN] Обнаружена попытка добавить забаненного пользователя ${invitedUserId} в беседу ${message.peer_id}`);
          
            // Немедленно кикаем
            try {
              await vk.api.messages.removeChatUser({
                chat_id: message.peer_id - 2000000000,
                member_id: invitedUserId
              });
            
              console.log(`[SYSBAN] Забаненный пользователь ${invitedUserId} автоматически кикнут из беседы ${message.peer_id}`);
            
              // Отправляем уведомление в беседу
              await vk.api.messages.send({
                peer_id: message.peer_id,
                message: `🚫 Пользователь [id${invitedUserId}|заблокирован] в системе бота и не может быть добавлен в беседы.`,
                random_id: Math.floor(Math.random() * 1e9),
                disable_mentions: true
              });
            } catch (kickError) {
              console.error(`[SYSBAN] Ошибка при автоматическом кике:`, kickError);
            }
          }
        }
      }
    };
  
    // Подключаем обработчик (способ подключения зависит от вашей архитектуры)
    // vk.updates.on('message_new', eventHandler);
    console.log('[SYSBAN] Автоматический кик настроен');
  
  } catch (error) {
    console.error('[SYSBAN] Ошибка настройки авто-кика:', error);
  }
}
// Запускаем авто-кик
setupAutoKick();
// Очистка старых записей раз в час
setInterval(() => {
  const now = Date.now();
  for (const [userId, data] of commandUsage.entries()) {
    if (data.blockedUntil < now && now - data.lastReset > 3600000) { // если блокировка прошла и прошёл час
      commandUsage.delete(userId);
    }
  }
}, 3600000); // Каждый час
module.exports = {
  command: '/sysban',
  description: 'Блокировка пользователя в системе бота (2 степени)',
  async execute(context) {
    try {
      // Проверка лимита использования
      const limitCheck = checkCommandLimit(context.senderId);
      if (!limitCheck.allowed) {
        return context.reply(limitCheck.message);
      }
      const hasAccess = await hasCommandAccess(context.senderId, 'sysban');
      if (!hasAccess) return context.reply(getAccessDeniedMessage('sysban'));
      const args = context.text.split(' ');
      if (args.length < 4) return context.reply('❌ Использование:\n/sysban [ID] [1|2] [дни|0] [причина]');
      const userId = await extractNumericId(args[1]);
      if (!userId) return context.reply('❌ Ошибка | Некорректный ID пользователя');
      if (userId === context.senderId) return context.reply('❌ Ошибка | Нельзя заблокировать самого себя');
      if (global.botId && Number(userId) === Number(global.botId)) return context.reply('🤖 Нельзя заблокировать бота');
      const senderAccess = await checkSysAccess(context.senderId);
      let targetAccess = 0;
      try { targetAccess = await checkSysAccess(userId); } catch {}
      if (targetAccess >= senderAccess && targetAccess > 0) {
        return context.reply(`❌ Ошибка | Вы не можете заблокировать пользователя с уровнем "${getAccessLevelName(targetAccess)}"`);
      }
      const banLevel = parseInt(args[2]);
      if (![1, 2].includes(banLevel)) return context.reply('❌ Уровень ЧСБ может быть только 1 или 2');
      const banDays = parseInt(args[3]);
      if (isNaN(banDays) || banDays < 0) return context.reply('❌ Некорректный срок блокировки');
      const reason = args.slice(4).join(' ') || 'Не указана';
      const now = Math.floor(Date.now() / 1000);
      const endTime = banDays === 0 ? 0 : now + banDays * 86400;
      const query = `
        INSERT INTO sysbanned (userid, time, reason, who, level)
        VALUES (?, ?, ?, ?, ?)
        ON DUPLICATE KEY UPDATE
          time = VALUES(time),
          reason = VALUES(reason),
          who = VALUES(who),
          level = VALUES(level)
      `;
      await databaseQuery(query, [userId, endTime, reason, context.senderId, banLevel]);
      // Обновляем кэш сразу после бана
      if (banLevel === 2) {
        bannedUsersCache.set(Number(userId), {
          level: 2,
          time: endTime
        });
      }
      let userDisplay = `@id${userId}`;
      try {
        const u = (await vk.api.users.get({ user_ids: userId }))[0];
        if (u) userDisplay = `[id${userId}|${u.first_name} ${u.last_name}]`;
      } catch {}
      const banType = banLevel === 1 ? '🚫 Запрет команд' : '⛔ Полный запрет бота';
      let message = `🚨 ${userDisplay} заблокирован в системе бота\n\n`;
      message += `🔐 Тип: ${banType}\n`;
      message += `🕒 Срок: ${banDays === 0 ? 'Навсегда' : banDays + ' дн.'}\n`;
      message += `📝 Причина: ${reason}`;
      await context.send({ message, disable_mentions: true });
      try {
        await vk.api.messages.send({
          peer_id: userId,
          message,
          random_id: Math.floor(Math.random() * 1e9),
          disable_mentions: true
        });
      } catch {}
      // Если это полный запрет (уровень 2), кикаем пользователя из всех бесед
      if (banLevel === 2) {
        const { kickedCount, errors } = await kickUserFromAllChats(userId);
      
        // Отправляем подробное сообщение о результате кика
        let kickMessage = '';
        if (kickedCount > 0) {
          kickMessage = `👢 Пользователь ${userDisplay} был кикнут из ${kickedCount} бесед`;
        } else {
          kickMessage = `⚠️ Пользователь ${userDisplay} не был найден в беседах`;
        }
      
        if (errors.length > 0) {
          kickMessage += `\n\n❌ Ошибки (${errors.length}):\n`;
          // Показываем только первые 3 ошибки
          errors.slice(0, 3).forEach(err => {
            kickMessage += `• ${err}\n`;
          });
        }
      
        await context.send({
          message: kickMessage,
          disable_mentions: true
        });
        // Запускаем дополнительную проверку через 5 секунд
        // (на случай, если пользователь был онлайн и не сразу кикнулся)
        setTimeout(async () => {
          console.log(`[SYSBAN] Повторная проверка пользователя ${userId} через 5 секунд`);
          const { kickedCount: additionalKicks } = await kickUserFromAllChats(userId);
          if (additionalKicks > 0) {
            await context.send({
              message: `👢 Дополнительно кикнуто из ${additionalKicks} бесед (повторная проверка)`,
              disable_mentions: true
            });
          }
        }, 5000);
      }
      // Сбрасываем счетчик после успешного выполнения
      const userUsage = commandUsage.get(context.senderId);
      if (userUsage) {
        userUsage.count = 0;
        userUsage.lastReset = Date.now();
        commandUsage.set(context.senderId, userUsage);
      }
    } catch (error) {
      console.error('SYSBAN ERROR:', error);
      context.reply('❌ Ошибка выполнения sysban');
    }
  }
};
// Экспортируем кэш для использования в других модулях
module.exports.bannedUsersCache = bannedUsersCache;
module.exports.isUserBanned = (userId) => bannedUsersCache.has(Number(userId));

вот что в index что я сделал:
Код:
// ============ Запрет на добавление забаненных (MySQL Версия) ============
async function checkAndKickBannedUser(peerId, newUserId, inviterId) {
  try {
    const now = Math.floor(Date.now() / 1000);
  
    // Прямой запрос в базу данных: ищем активный бан 2-го уровня (Полный запрет)
    const banCheck = await queryAsync(
      'SELECT level FROM sysbanned WHERE userid = ? AND level = 2 AND (time = 0 OR time > ?)',
      [Number(newUserId), now]
    );
    // Если нашли активный бан 2-го уровня — жестко кикаем
    if (banCheck && banCheck.length > 0) {
      // Исключаем пользователя средствами vk.api
      try {
        await vk.api.messages.removeChatUser({
          chat_id: peerId - 2000000000,
          user_id: newUserId
        });
      } catch (kickError) {
        console.error(`[SYSBAN] Не удалось кикнуть ${newUserId}:`, kickError.message);
      }
      // Получаем имя пользователя для красивого вывода
      let userName = `@id${newUserId}`;
      try {
        const u = (await vk.api.users.get({ user_ids: newUserId }))[0];
        if (u) userName = `[id${newUserId}|${u.first_name} ${u.last_name}]`;
      } catch (e) {}
      // Отправляем уведомление в чат
      try {
        await vk.api.messages.send({
          peer_id: peerId,
          message: `${userName} находится в чёрном списке бота (Полный запрет), он(а) исключен(а) из соображений безопасности.\n\nОбратите внимание, обратное добавление этого пользователя в беседу будет расценено как подозрительное действие, приглашающий участник будет исключен.`,
          random_id: Math.floor(Math.random() * 1e9),
          disable_mentions: true
        });
      } catch (e) {}
      return;
    }
    // Проверка локального бана в конкретной беседе (из punishments)
    try {
      const { isBanned: cb } = require('./cmds/punishments.js');
      if (typeof cb === 'function' && cb(peerId, newUserId)) {
        try {
          await vk.api.messages.removeChatUser({ chat_id: peerId - 2000000000, user_id: newUserId });
          await vk.api.messages.send({
            peer_id: peerId,
            message: `@id${newUserId} забанен в этой беседе.`,
            random_id: Math.floor(Math.random() * 1e9)
          });
        } catch (e) {}
      }
    } catch (e) {}
  } catch (error) {
    console.error('[SYSBAN AUTOCHECK ERROR]:', error);
  }
}
// Перехватчик ручного приглашения (инвайта)
vk.updates.on('chat_invite_user', async function(ctx, next) {
  if (ctx.eventMemberId === -ctx.groupId) return next();
  await checkAndKickBannedUser(ctx.peerId, ctx.eventMemberId, ctx.senderId);
  await next();
});
// Перехватчик для тех, кто заходит САМ по ссылке (в обход инвайта)
vk.updates.on('message_new', async (ctx, next) => {
  try {
    if (ctx.action && ctx.action.type === 'chat_invite_user') {
      const targetId = Number(ctx.action.member_id);
      if (targetId > 0) {
        await checkAndKickBannedUser(ctx.peerId, targetId, ctx.senderId);
      }
    }
  } catch (e) {
    console.error('[LINK INBOUND ERROR]:', e);
  }
  await next();
});
// Автоматический фоновый сканер (вычищает чаты, если ВК вообще не прислал событие входа)
setInterval(async function() {
  try {
    const confs = global.database && global.database.data ? (global.database.data.conference || []) : [];
    const now = Math.floor(Date.now() / 1000);
    for (let i = 0; i < confs.length; i++) {
      try {
        const currentPeerId = confs[i].conference_id;
        const mems = await vk.api.messages.getConversationMembers({ peer_id: currentPeerId });
        for (let j = 0; j < (mems.items || []).length; j++) {
          const currentMemberId = mems.items[j].member_id;
          if (currentMemberId > 0) {
            // Проверяем каждого участника прямо в MySQL
            const check = await queryAsync(
              'SELECT level FROM sysbanned WHERE userid = ? AND level = 2 AND (time = 0 OR time > ?)',
              [Number(currentMemberId), now]
            );
            if (check && check.length > 0) {
              try {
                await vk.api.messages.removeChatUser({ chat_id: currentPeerId - 2000000000, user_id: currentMemberId });
              
                let userName = `@id${currentMemberId}`;
                try {
                  const u = (await vk.api.users.get({ user_ids: currentMemberId }))[0];
                  if (u) userName = `[id${currentMemberId}|${u.first_name} ${u.last_name}]`;
                } catch (e) {}
                await vk.api.messages.send({
                  peer_id: currentPeerId,
                  message: `${userName} обнаружен в чёрном списке бота (Полный запрет) и автоматически удалён.`,
                  random_id: Math.floor(Math.random() * 1e9),
                  disable_mentions: true
                });
              } catch (e) {}
            }
          }
        }
      } catch (e) {}
      await new Promise(r => setTimeout(r, 400));
    }
  } catch (e) {}
}, 30000);
 
Сверху