const crypto = require('crypto'); const User = require('../models/User'); const { validateTelegramId } = require('./validator'); const { logSecurityEvent } = require('./logger'); const config = require('../config'); // Проверка Telegram Init Data function validateTelegramWebAppData(initData, botToken) { const urlParams = new URLSearchParams(initData); const hash = urlParams.get('hash'); urlParams.delete('hash'); const dataCheckString = Array.from(urlParams.entries()) .sort(([a], [b]) => a.localeCompare(b)) .map(([key, value]) => `${key}=${value}`) .join('\n'); const secretKey = crypto .createHmac('sha256', 'WebAppData') .update(botToken) .digest(); const calculatedHash = crypto .createHmac('sha256', secretKey) .update(dataCheckString) .digest('hex'); return calculatedHash === hash; } // Middleware для проверки авторизации const authenticate = async (req, res, next) => { try { const initData = req.headers['x-telegram-init-data']; if (!initData) { console.warn('⚠️ Нет x-telegram-init-data заголовка'); return res.status(401).json({ error: 'Не авторизован' }); } // Получаем user из initData let urlParams; try { urlParams = new URLSearchParams(initData); } catch (e) { // Если initData не URLSearchParams, попробуем как JSON try { const parsed = JSON.parse(initData); if (parsed.user) { req.telegramUser = parsed.user; // Найти или создать пользователя let user = await User.findOne({ telegramId: parsed.user.id.toString() }); if (!user) { user = new User({ telegramId: parsed.user.id.toString(), username: parsed.user.username || parsed.user.first_name, firstName: parsed.user.first_name, lastName: parsed.user.last_name, photoUrl: parsed.user.photo_url }); await user.save(); console.log(`✅ Создан новый пользователь: ${user.username}`); } req.user = user; return next(); } } catch (e2) { console.error('❌ Ошибка парсинга initData:', e2.message); return res.status(401).json({ error: 'Неверный формат данных авторизации' }); } } const userParam = urlParams.get('user'); if (!userParam) { console.warn('⚠️ Нет user параметра в initData'); return res.status(401).json({ error: 'Данные пользователя не найдены' }); } let telegramUser; try { telegramUser = JSON.parse(userParam); } catch (e) { console.error('❌ Ошибка парсинга user:', e.message); return res.status(401).json({ error: 'Ошибка парсинга данных пользователя' }); } req.telegramUser = telegramUser; // Валидация Telegram ID if (!validateTelegramId(telegramUser.id)) { logSecurityEvent('INVALID_TELEGRAM_ID', req, { telegramId: telegramUser.id }); return res.status(401).json({ error: 'Неверный ID пользователя' }); } // Проверка подписи Telegram (строгая проверка в production) if (config.telegramBotToken) { const isValid = validateTelegramWebAppData(initData, config.telegramBotToken); if (!isValid) { logSecurityEvent('INVALID_TELEGRAM_SIGNATURE', req, { telegramId: telegramUser.id, hasToken: !!config.telegramBotToken }); // В production строгая проверка if (config.isProduction()) { return res.status(401).json({ error: 'Неверные данные авторизации' }); } } } else if (config.isProduction()) { logSecurityEvent('MISSING_BOT_TOKEN', req); console.warn('⚠️ TELEGRAM_BOT_TOKEN не установлен, проверка подписи пропущена'); } // Найти или создать пользователя let user = await User.findOne({ telegramId: telegramUser.id.toString() }); if (!user) { user = new User({ telegramId: telegramUser.id.toString(), username: telegramUser.username || telegramUser.first_name, firstName: telegramUser.first_name, lastName: telegramUser.last_name, photoUrl: telegramUser.photo_url }); await user.save(); console.log(`✅ Создан новый пользователь: ${user.username}`); } req.user = user; next(); } catch (error) { console.error('❌ Ошибка авторизации:', error); res.status(401).json({ error: 'Ошибка авторизации' }); } }; // Middleware для проверки роли модератора const requireModerator = (req, res, next) => { if (req.user.role !== 'moderator' && req.user.role !== 'admin') { return res.status(403).json({ error: 'Требуются права модератора' }); } next(); }; // Middleware для проверки роли админа const requireAdmin = (req, res, next) => { if (req.user.role !== 'admin') { return res.status(403).json({ error: 'Требуются права администратора' }); } next(); }; module.exports = { authenticate, requireModerator, requireAdmin };