Update files
This commit is contained in:
parent
fc7c4c6561
commit
b6036af3f1
|
|
@ -221,35 +221,9 @@ router.post('/oauth', strictAuthLimiter, async (req, res) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Проверка авторизации и получение данных пользователя
|
|
||||||
const { authenticate } = require('../middleware/auth');
|
|
||||||
|
|
||||||
router.post('/verify', authenticate, async (req, res) => {
|
router.post('/verify', authenticate, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const user = await req.user.populate([
|
return respondWithUser(req.user, res);
|
||||||
{ 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
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Ошибка verify:', error);
|
console.error('Ошибка verify:', error);
|
||||||
res.status(500).json({ error: 'Ошибка сервера' });
|
res.status(500).json({ error: 'Ошибка сервера' });
|
||||||
|
|
|
||||||
|
|
@ -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 config = require('../config');
|
||||||
|
|
||||||
const MAX_AUTH_AGE_SECONDS = 5 * 60;
|
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) {
|
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) {
|
if (!config.telegramBotToken) {
|
||||||
throw new Error('TELEGRAM_BOT_TOKEN не настроен');
|
throw new Error('TELEGRAM_BOT_TOKEN не настроен');
|
||||||
}
|
}
|
||||||
|
|
@ -18,14 +64,43 @@ function validateAndParseInitData(initDataRaw) {
|
||||||
throw new Error('initData пуст');
|
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) {
|
if (!valid) {
|
||||||
|
console.error('[Telegram] All validation attempts failed');
|
||||||
throw new Error('Неверная подпись initData');
|
throw new Error('Неверная подпись initData');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('[Telegram] initData validation successful, parsing...');
|
||||||
|
|
||||||
const payload = parse(trimmed);
|
const payload = parse(trimmed);
|
||||||
|
|
||||||
|
console.log('[Telegram] Parsed payload:', {
|
||||||
|
hasUser: !!payload?.user,
|
||||||
|
userId: payload?.user?.id,
|
||||||
|
authDate: payload?.auth_date
|
||||||
|
});
|
||||||
|
|
||||||
if (!payload || !payload.user) {
|
if (!payload || !payload.user) {
|
||||||
throw new Error('Отсутствует пользователь в initData');
|
throw new Error('Отсутствует пользователь в initData');
|
||||||
}
|
}
|
||||||
|
|
@ -42,6 +117,8 @@ function validateAndParseInitData(initDataRaw) {
|
||||||
throw new Error('Данные авторизации устарели');
|
throw new Error('Данные авторизации устарели');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('[Telegram] initData validation complete');
|
||||||
|
|
||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,15 @@ const api = axios.create({
|
||||||
|
|
||||||
api.interceptors.request.use((config) => {
|
api.interceptors.request.use((config) => {
|
||||||
const initData = window.Telegram?.WebApp?.initData;
|
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) {
|
if (initData) {
|
||||||
config.headers = config.headers || {};
|
config.headers = config.headers || {};
|
||||||
if (!config.headers.Authorization) {
|
if (!config.headers.Authorization) {
|
||||||
|
|
@ -26,7 +35,10 @@ api.interceptors.request.use((config) => {
|
||||||
if (!config.headers['x-telegram-init-data']) {
|
if (!config.headers['x-telegram-init-data']) {
|
||||||
config.headers['x-telegram-init-data'] = initData;
|
config.headers['x-telegram-init-data'] = initData;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('[API] No initData available for request:', config.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
"xss-clean": "^0.1.4",
|
"xss-clean": "^0.1.4",
|
||||||
"hpp": "^0.2.3",
|
"hpp": "^0.2.3",
|
||||||
"validator": "^13.11.0",
|
"validator": "^13.11.0",
|
||||||
"@telegram-apps/init-data-node": "^1.0.0"
|
"@telegram-apps/init-data-node": "^1.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"nodemon": "^3.0.1",
|
"nodemon": "^3.0.1",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue