const User = require('../models/User'); const { validateTelegramId } = require('./validator'); const { logSecurityEvent } = require('./logger'); const config = require('../config'); const { ACCESS_COOKIE, REFRESH_COOKIE, signAuthTokens, setAuthCookies, clearAuthCookies, verifyAccessToken, verifyRefreshToken } = require('../utils/tokens'); const OFFICIAL_CLIENT_MESSAGE = 'Используйте официальный клиент. Сообщите об ошибке в https://t.me/NakamaReportbot'; const ALLOWED_SEARCH_PREFERENCES = ['furry', 'anime']; const touchUserActivity = async (user) => { if (!user) return; const now = Date.now(); const shouldUpdate = !user.lastActiveAt || Math.abs(now - new Date(user.lastActiveAt).getTime()) > 5 * 60 * 1000; if (shouldUpdate) { user.lastActiveAt = new Date(now); await user.save(); } }; const ensureUserSettings = async (user) => { if (!user) return; let updated = false; if (!user.settings) { user.settings = {}; updated = true; } if (!ALLOWED_SEARCH_PREFERENCES.includes(user.settings.searchPreference)) { user.settings.searchPreference = 'furry'; updated = true; } if (!user.settings.whitelist) { user.settings.whitelist = { noNSFW: true }; updated = true; } else if (user.settings.whitelist.noNSFW === undefined) { user.settings.whitelist.noNSFW = true; updated = true; } if (updated) { user.markModified('settings'); await user.save(); } }; // Middleware для проверки авторизации const authenticate = async (req, res, next) => { try { const accessToken = req.cookies[ACCESS_COOKIE]; const refreshToken = req.cookies[REFRESH_COOKIE]; let tokenPayload = null; if (accessToken) { try { tokenPayload = verifyAccessToken(accessToken); } catch (error) { if (error.name !== 'TokenExpiredError') { logSecurityEvent('INVALID_ACCESS_TOKEN', req, { error: error.message }); clearAuthCookies(res); return res.status(401).json({ error: OFFICIAL_CLIENT_MESSAGE }); } } } if (!tokenPayload && refreshToken) { try { const refreshPayload = verifyRefreshToken(refreshToken); const userForRefresh = await User.findById(refreshPayload.userId); if (!userForRefresh) { clearAuthCookies(res); return res.status(401).json({ error: OFFICIAL_CLIENT_MESSAGE }); } const tokens = signAuthTokens(userForRefresh); setAuthCookies(res, tokens); tokenPayload = verifyAccessToken(tokens.accessToken); } catch (error) { logSecurityEvent('INVALID_REFRESH_TOKEN', req, { error: error.message }); clearAuthCookies(res); return res.status(401).json({ error: OFFICIAL_CLIENT_MESSAGE }); } } if (!tokenPayload) { logSecurityEvent('AUTH_TOKEN_MISSING', req); return res.status(401).json({ error: OFFICIAL_CLIENT_MESSAGE }); } if (!validateTelegramId(tokenPayload.telegramId)) { logSecurityEvent('INVALID_TELEGRAM_ID', req, { telegramId: tokenPayload.telegramId }); clearAuthCookies(res); return res.status(401).json({ error: 'Неверный ID пользователя' }); } let user = await User.findOne({ telegramId: tokenPayload.telegramId.toString() }); if (!user) { clearAuthCookies(res); return res.status(401).json({ error: OFFICIAL_CLIENT_MESSAGE }); } if (user.banned) { clearAuthCookies(res); return res.status(403).json({ error: 'Пользователь заблокирован' }); } await ensureUserSettings(user); await touchUserActivity(user); req.user = user; req.telegramUser = { id: user.telegramId }; next(); } catch (error) { console.error('❌ Ошибка авторизации:', error); res.status(401).json({ error: `Ошибка авторизации. ${OFFICIAL_CLIENT_MESSAGE}` }); } }; // 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, touchUserActivity, ensureUserSettings };