nakama/backend/routes/auth.js

160 lines
5.3 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 express = require('express');
const router = express.Router();
const crypto = require('crypto');
const User = require('../models/User');
const config = require('../config');
const { validateTelegramId } = require('../middleware/validator');
const { logSecurityEvent } = require('../middleware/logger');
const { strictAuthLimiter } = require('../middleware/security');
// Проверка подписи Telegram OAuth (Login Widget)
function validateTelegramOAuth(authData, botToken) {
if (!authData || !authData.hash) {
return false;
}
const { hash, ...data } = authData;
const dataCheckString = Object.keys(data)
.sort()
.map(key => `${key}=${data[key]}`)
.join('\n');
const secretKey = crypto
.createHmac('sha256', 'WebAppData')
.update(botToken)
.digest();
const calculatedHash = crypto
.createHmac('sha256', secretKey)
.update(dataCheckString)
.digest('hex');
return calculatedHash === hash;
}
// Авторизация через Telegram OAuth (Login Widget)
router.post('/oauth', strictAuthLimiter, async (req, res) => {
try {
const { user: telegramUser, auth_date, hash } = req.body;
if (!telegramUser || !auth_date || !hash) {
logSecurityEvent('INVALID_OAUTH_DATA', req);
return res.status(400).json({ error: 'Неверные данные авторизации' });
}
// Валидация Telegram ID
if (!validateTelegramId(telegramUser.id)) {
logSecurityEvent('INVALID_TELEGRAM_ID', req, { telegramId: telegramUser.id });
return res.status(400).json({ error: 'Неверный ID пользователя' });
}
// Проверка подписи Telegram (строгая проверка в production)
if (config.telegramBotToken) {
const authData = {
id: telegramUser.id,
first_name: telegramUser.first_name,
last_name: telegramUser.last_name,
username: telegramUser.username,
photo_url: telegramUser.photo_url,
auth_date: auth_date,
hash: hash
};
const isValid = validateTelegramOAuth(authData, config.telegramBotToken);
if (!isValid) {
logSecurityEvent('INVALID_OAUTH_SIGNATURE', req, { telegramId: telegramUser.id });
// В production строгая проверка
if (config.isProduction()) {
return res.status(401).json({ error: 'Неверная подпись Telegram OAuth' });
}
}
}
// Найти или создать пользователя
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(`✅ Создан новый пользователь через OAuth: ${user.username}`);
} else {
// Обновить данные пользователя
user.username = telegramUser.username || telegramUser.first_name;
user.firstName = telegramUser.first_name;
user.lastName = telegramUser.last_name;
user.photoUrl = telegramUser.photo_url;
await user.save();
}
// Получить полные данные пользователя
const populatedUser = await User.findById(user._id).populate([
{ path: 'followers', select: 'username firstName lastName photoUrl' },
{ path: 'following', select: 'username firstName lastName photoUrl' }
]);
res.json({
success: true,
user: {
id: populatedUser._id,
telegramId: populatedUser.telegramId,
username: populatedUser.username,
firstName: populatedUser.firstName,
lastName: populatedUser.lastName,
photoUrl: populatedUser.photoUrl,
bio: populatedUser.bio,
role: populatedUser.role,
followersCount: populatedUser.followers.length,
followingCount: populatedUser.following.length,
settings: populatedUser.settings,
banned: populatedUser.banned
}
});
} catch (error) {
console.error('Ошибка OAuth:', error);
res.status(500).json({ error: 'Ошибка сервера' });
}
});
// Проверка авторизации и получение данных пользователя
const { authenticate } = require('../middleware/auth');
router.post('/verify', authenticate, async (req, res) => {
try {
const user = await req.user.populate([
{ path: 'followers', select: 'username firstName lastName photoUrl' },
{ path: 'following', select: 'username firstName lastName photoUrl' }
]);
res.json({
success: true,
user: {
id: user._id,
telegramId: user.telegramId,
username: user.username,
firstName: user.firstName,
lastName: user.lastName,
photoUrl: user.photoUrl,
bio: user.bio,
role: user.role,
followersCount: user.followers.length,
followingCount: user.following.length,
settings: user.settings,
banned: user.banned
}
});
} catch (error) {
console.error('Ошибка verify:', error);
res.status(500).json({ error: 'Ошибка сервера' });
}
});
module.exports = router;