nakama/backend/middleware/auth.js

105 lines
3.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
};