Spaces:
Paused
Paused
Download apps/api/src/core/telegram.js from nenbuj/we-superapp: direct link, hf CLI and curl.
- Browser
- Download file 1.88 kB
-
https://huggingface.co/spaces/nenbuj/we-superapp/resolve/main/apps/api/src/core/telegram.js
- Command line
-
hf download hf://spaces/nenbuj/we-superapp/apps/api/src/core/telegram.js
-
curl -L -o telegram.js https://huggingface.co/spaces/nenbuj/we-superapp/resolve/main/apps/api/src/core/telegram.js
1.88 kB
| // Ядро: валидация Telegram WebApp initData. Ведёт Claude. | |
| // Алгоритм по докам Telegram: | |
| // secret_key = HMAC_SHA256(key="WebAppData", message=BOT_TOKEN) | |
| // hash = HMAC_SHA256(key=secret_key, message=data_check_string) | |
| // data_check_string — пары "key=value" (без hash), отсортированные по ключу, через '\n'. | |
| import crypto from 'node:crypto'; | |
| export const BOT_TOKEN = process.env.BOT_TOKEN || ''; | |
| // Возвращает объект пользователя Telegram при валидной подписи, иначе null. | |
| // maxAgeSec — защита от старых initData (по умолчанию 24ч). | |
| export function validateInitData(initData, maxAgeSec = 86400) { | |
| if (!BOT_TOKEN || !initData) return null; | |
| const params = new URLSearchParams(initData); | |
| const hash = params.get('hash'); | |
| if (!hash) return null; | |
| params.delete('hash'); | |
| const dataCheckString = [...params.entries()] | |
| .map(([k, v]) => `${k}=${v}`) | |
| .sort() | |
| .join('\n'); | |
| const secretKey = crypto.createHmac('sha256', 'WebAppData').update(BOT_TOKEN).digest(); | |
| const computed = crypto.createHmac('sha256', secretKey).update(dataCheckString).digest('hex'); | |
| // сравнение в постоянное время | |
| const a = Buffer.from(computed, 'hex'); | |
| const b = Buffer.from(hash, 'hex'); | |
| if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) return null; | |
| // проверка свежести | |
| const authDate = Number(params.get('auth_date') || 0); | |
| if (authDate && Date.now() / 1000 - authDate > maxAgeSec) return null; | |
| // user приходит JSON-строкой | |
| try { | |
| const user = JSON.parse(params.get('user') || 'null'); | |
| if (!user || !user.id) return null; | |
| return user; // { id, first_name, last_name?, username?, ... } | |
| } catch { | |
| return null; | |
| } | |
| } | |