Update files
This commit is contained in:
parent
d6fcfc5c17
commit
d2361b0e10
|
|
@ -36,20 +36,27 @@ const OFFICIAL_CLIENT_MESSAGE = 'Используйте официальный
|
|||
|
||||
router.post('/signin', strictAuthLimiter, async (req, res) => {
|
||||
try {
|
||||
const { initData } = req.body || {};
|
||||
const authHeader = req.headers.authorization || '';
|
||||
const headerInitData = authHeader.startsWith('tma ') ? authHeader.slice(4).trim() : null;
|
||||
const bodyInitData = typeof req.body?.initData === 'string' ? req.body.initData : null;
|
||||
|
||||
if (!initData || typeof initData !== 'string') {
|
||||
const initDataRaw = headerInitData || bodyInitData;
|
||||
|
||||
if (!initDataRaw) {
|
||||
return res.status(400).json({ error: 'initData обязателен' });
|
||||
}
|
||||
|
||||
let telegramUser;
|
||||
let payload;
|
||||
|
||||
try {
|
||||
({ telegramUser } = validateAndParseInitData(initData, req));
|
||||
payload = validateAndParseInitData(initDataRaw);
|
||||
} catch (error) {
|
||||
logSecurityEvent('INVALID_INITDATA', req, { reason: error.message });
|
||||
return res.status(401).json({ error: error.message });
|
||||
}
|
||||
|
||||
const telegramUser = payload.user;
|
||||
|
||||
if (!validateTelegramId(telegramUser.id)) {
|
||||
logSecurityEvent('INVALID_TELEGRAM_ID', req, { telegramId: telegramUser.id });
|
||||
return res.status(400).json({ error: 'Неверный ID пользователя' });
|
||||
|
|
|
|||
|
|
@ -1,64 +1,48 @@
|
|||
const crypto = require('crypto');
|
||||
const { parse, isValid } = require('@telegram-apps/init-data-node');
|
||||
const config = require('../config');
|
||||
|
||||
const MAX_AUTH_AGE_SECONDS = 5 * 60;
|
||||
|
||||
function validateAndParseInitData(initData, req) {
|
||||
function validateAndParseInitData(initDataRaw) {
|
||||
if (!config.telegramBotToken) {
|
||||
throw new Error('TELEGRAM_BOT_TOKEN не настроен');
|
||||
}
|
||||
|
||||
const params = new URLSearchParams(initData);
|
||||
const hash = params.get('hash');
|
||||
const authDate = Number(params.get('auth_date'));
|
||||
|
||||
if (!hash) {
|
||||
throw new Error('Отсутствует hash в initData');
|
||||
if (!initDataRaw || typeof initDataRaw !== 'string') {
|
||||
throw new Error('initData не передан');
|
||||
}
|
||||
|
||||
const trimmed = initDataRaw.trim();
|
||||
|
||||
if (!trimmed.length) {
|
||||
throw new Error('initData пуст');
|
||||
}
|
||||
|
||||
const valid = isValid(trimmed, config.telegramBotToken);
|
||||
|
||||
if (!valid) {
|
||||
throw new Error('Неверная подпись initData');
|
||||
}
|
||||
|
||||
const payload = parse(trimmed);
|
||||
|
||||
if (!payload || !payload.user) {
|
||||
throw new Error('Отсутствует пользователь в initData');
|
||||
}
|
||||
|
||||
const authDate = Number(payload.auth_date);
|
||||
|
||||
if (!authDate) {
|
||||
throw new Error('Отсутствует auth_date в initData');
|
||||
}
|
||||
|
||||
const dataCheck = [];
|
||||
for (const [key, value] of params.entries()) {
|
||||
if (key === 'hash') continue;
|
||||
dataCheck.push(`${key}=${value}`);
|
||||
}
|
||||
|
||||
dataCheck.sort((a, b) => a.localeCompare(b));
|
||||
const dataCheckString = dataCheck.join('\n');
|
||||
|
||||
const secretKey = crypto.createHmac('sha256', 'WebAppData').update(config.telegramBotToken).digest();
|
||||
const calculatedHash = crypto.createHmac('sha256', secretKey).update(dataCheckString).digest('hex');
|
||||
|
||||
if (calculatedHash !== hash) {
|
||||
throw new Error('Неверная подпись initData');
|
||||
}
|
||||
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
|
||||
if (Math.abs(now - authDate) > MAX_AUTH_AGE_SECONDS) {
|
||||
throw new Error('Данные авторизации устарели');
|
||||
}
|
||||
|
||||
const userParam = params.get('user');
|
||||
|
||||
if (!userParam) {
|
||||
throw new Error('Отсутствует пользователь в initData');
|
||||
}
|
||||
|
||||
let telegramUser;
|
||||
try {
|
||||
telegramUser = JSON.parse(userParam);
|
||||
} catch (error) {
|
||||
throw new Error('Некорректный формат user в initData');
|
||||
}
|
||||
|
||||
if (!telegramUser || !telegramUser.id) {
|
||||
throw new Error('Отсутствует ID пользователя в initData');
|
||||
}
|
||||
|
||||
return { params, telegramUser };
|
||||
return payload;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,17 @@ const api = axios.create({
|
|||
}
|
||||
})
|
||||
|
||||
api.interceptors.request.use((config) => {
|
||||
const initData = window.Telegram?.WebApp?.initData;
|
||||
if (initData) {
|
||||
config.headers = config.headers || {};
|
||||
if (!config.headers.Authorization) {
|
||||
config.headers.Authorization = `tma ${initData}`;
|
||||
}
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
||||
// Auth API
|
||||
export const signInWithTelegram = async (initData) => {
|
||||
const response = await api.post('/auth/signin', { initData })
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<title>Nakama Moderation</title>
|
||||
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,17 @@ const api = axios.create({
|
|||
withCredentials: true
|
||||
})
|
||||
|
||||
api.interceptors.request.use((config) => {
|
||||
const initData = window.Telegram?.WebApp?.initData;
|
||||
if (initData) {
|
||||
config.headers = config.headers || {};
|
||||
if (!config.headers.Authorization) {
|
||||
config.headers.Authorization = `tma ${initData}`;
|
||||
}
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
||||
export const signInWithTelegram = (initData) =>
|
||||
api.post('/auth/signin', { initData }).then((res) => res.data.user)
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@
|
|||
"xss-clean": "^0.1.4",
|
||||
"hpp": "^0.2.3",
|
||||
"validator": "^13.11.0",
|
||||
"cookie-parser": "^1.4.6"
|
||||
"cookie-parser": "^1.4.6",
|
||||
"@telegram-apps/init-data-node": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.0.1",
|
||||
|
|
|
|||
Loading…
Reference in New Issue