diff --git a/backend/routes/auth.js b/backend/routes/auth.js index b8f77ff..3fd3878 100644 --- a/backend/routes/auth.js +++ b/backend/routes/auth.js @@ -221,35 +221,9 @@ router.post('/oauth', strictAuthLimiter, async (req, res) => { } }); -// Проверка авторизации и получение данных пользователя -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' } - ]); - - const settings = normalizeUserSettings(user.settings); - - 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, - banned: user.banned - } - }); + return respondWithUser(req.user, res); } catch (error) { console.error('Ошибка verify:', error); res.status(500).json({ error: 'Ошибка сервера' }); diff --git a/backend/utils/telegram.js b/backend/utils/telegram.js index 79b559d..2f3da9d 100644 --- a/backend/utils/telegram.js +++ b/backend/utils/telegram.js @@ -1,9 +1,55 @@ -const { parse, isValid } = require('@telegram-apps/init-data-node'); +const { parse, validate } = require('@telegram-apps/init-data-node'); +const crypto = require('crypto'); const config = require('../config'); const MAX_AUTH_AGE_SECONDS = 5 * 60; +/** + * Manual validation with base64 padding fix + * Based on: https://docs.telegram-mini-apps.com/platform/init-data + */ +function manualValidateInitData(initDataRaw, botToken) { + const params = new URLSearchParams(initDataRaw); + const hash = params.get('hash'); + + if (!hash) { + throw new Error('Отсутствует hash в initData'); + } + + // Remove hash from params + params.delete('hash'); + + // Create data check string + const dataCheckArr = Array.from(params.entries()) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([key, value]) => `${key}=${value}`); + + const dataCheckString = dataCheckArr.join('\n'); + + // Create secret key + const secretKey = crypto + .createHmac('sha256', 'WebAppData') + .update(botToken) + .digest(); + + // Create signature + const signature = crypto + .createHmac('sha256', secretKey) + .update(dataCheckString) + .digest('hex'); + + // Compare signatures + return signature === hash; +} + function validateAndParseInitData(initDataRaw) { + console.log('[Telegram] validateAndParseInitData called:', { + hasInitData: !!initDataRaw, + type: typeof initDataRaw, + length: initDataRaw?.length || 0, + preview: initDataRaw?.substring(0, 100) + '...' + }); + if (!config.telegramBotToken) { throw new Error('TELEGRAM_BOT_TOKEN не настроен'); } @@ -18,14 +64,43 @@ function validateAndParseInitData(initDataRaw) { throw new Error('initData пуст'); } - const valid = isValid(trimmed, config.telegramBotToken); + console.log('[Telegram] Validating initData with bot token...'); + + // Try library validation first + let valid = false; + try { + validate(trimmed, config.telegramBotToken); + valid = true; + console.log('[Telegram] Library validation successful'); + } catch (libError) { + console.log('[Telegram] Library validation failed, trying manual validation:', libError.message); + + // Fallback to manual validation with base64 padding fix + try { + valid = manualValidateInitData(trimmed, config.telegramBotToken); + if (valid) { + console.log('[Telegram] Manual validation successful'); + } + } catch (manualError) { + console.error('[Telegram] Manual validation also failed:', manualError.message); + } + } if (!valid) { + console.error('[Telegram] All validation attempts failed'); throw new Error('Неверная подпись initData'); } + console.log('[Telegram] initData validation successful, parsing...'); + const payload = parse(trimmed); + console.log('[Telegram] Parsed payload:', { + hasUser: !!payload?.user, + userId: payload?.user?.id, + authDate: payload?.auth_date + }); + if (!payload || !payload.user) { throw new Error('Отсутствует пользователь в initData'); } @@ -42,6 +117,8 @@ function validateAndParseInitData(initDataRaw) { throw new Error('Данные авторизации устарели'); } + console.log('[Telegram] initData validation complete'); + return payload; } diff --git a/frontend/src/utils/api.js b/frontend/src/utils/api.js index 0afd2d1..c0b908a 100644 --- a/frontend/src/utils/api.js +++ b/frontend/src/utils/api.js @@ -18,6 +18,15 @@ const api = axios.create({ api.interceptors.request.use((config) => { const initData = window.Telegram?.WebApp?.initData; + + console.log('[API] Request interceptor:', { + url: config.url, + method: config.method, + hasInitData: !!initData, + initDataLength: initData?.length || 0, + initDataPreview: initData?.substring(0, 50) + '...' + }); + if (initData) { config.headers = config.headers || {}; if (!config.headers.Authorization) { @@ -26,7 +35,10 @@ api.interceptors.request.use((config) => { if (!config.headers['x-telegram-init-data']) { config.headers['x-telegram-init-data'] = initData; } + } else { + console.warn('[API] No initData available for request:', config.url); } + return config; }); diff --git a/package.json b/package.json index bc325ec..6fd336c 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "xss-clean": "^0.1.4", "hpp": "^0.2.3", "validator": "^13.11.0", - "@telegram-apps/init-data-node": "^1.0.0" + "@telegram-apps/init-data-node": "^1.0.4" }, "devDependencies": { "nodemon": "^3.0.1",