105 lines
3.7 KiB
JavaScript
105 lines
3.7 KiB
JavaScript
const crypto = require('crypto');
|
||
const User = require('../models/User');
|
||
|
||
// Проверка 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) {
|
||
return res.status(401).json({ error: 'Не авторизован' });
|
||
}
|
||
|
||
// Получаем user из initData
|
||
const urlParams = new URLSearchParams(initData);
|
||
const userParam = urlParams.get('user');
|
||
|
||
if (!userParam) {
|
||
return res.status(401).json({ error: 'Данные пользователя не найдены' });
|
||
}
|
||
|
||
const telegramUser = JSON.parse(userParam);
|
||
req.telegramUser = telegramUser;
|
||
|
||
// Проверка подписи Telegram (только в production и если есть токен)
|
||
if (process.env.NODE_ENV === 'production' && process.env.TELEGRAM_BOT_TOKEN) {
|
||
const isValid = validateTelegramWebAppData(initData, process.env.TELEGRAM_BOT_TOKEN);
|
||
|
||
if (!isValid) {
|
||
console.warn('⚠️ Неверная подпись Telegram Init Data для пользователя:', telegramUser.id);
|
||
// В production можно либо отклонить, либо пропустить с предупреждением
|
||
// Для строгой проверки раскомментируйте:
|
||
// return res.status(401).json({ error: 'Неверные данные авторизации' });
|
||
}
|
||
} else if (process.env.NODE_ENV === 'production') {
|
||
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
|
||
};
|