Files
bedolaga-cabinet/src/utils/telegramInitData.ts
Fringg f81af401f7 fix(auth): читать initData из моста Telegram, а не только из кэша SDK
retrieveRawInitData() ищет параметры запуска по цепочке location.href ->
запись performance о навигации -> кэш tapps/launchParams в sessionStorage,
записывая удачный результат обратно. Последние два источника привязаны к
документу, а не к текущему запуску мини-аппы: как только SPA сменила
маршрут и hash с tgWebAppData ушёл из адреса, остаются данные ПЕРВОГО
запуска в этой сессии WebView. На iOS WebView переживает переоткрытия, и
SDK молча отдаёт старую копию.

Бэкенд принимает initData с auth_date не старше 30 суток, поэтому
застрявшая копия рано или поздно пересекает порог и вход отваливается с
«Invalid or expired Telegram authentication data».

Спрашиваем ещё и window.Telegram.WebApp.initData (официальный мост,
telegram-web-app.js из index.html) и берём вариант со свежим auth_date:
какой источник протух, зависит от платформы, «самый свежий» верен всегда.
Все три места чтения initData сведены в один модуль.
2026-08-19 02:00:41 +03:00

64 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { retrieveRawInitData } from '@telegram-apps/sdk-react';
/**
* Сырая строка initData Telegram, прочитанная в момент вызова.
*
* Почему мало одного `retrieveRawInitData()` из @telegram-apps/sdk: он ищет
* параметры запуска по цепочке `location.href` → запись performance о навигации
* → собственный кэш `tapps/launchParams` в sessionStorage, записывая удачный
* результат обратно в кэш. Последние два источника привязаны не к текущему
* запуску мини-аппы, а к документу: как только SPA сменила маршрут и hash с
* `tgWebAppData` ушёл из адреса, остаются запись о навигации исходного
* документа и кэш — оба из ПЕРВОГО запуска в этой сессии WebView. На iOS такой
* WebView переживает переоткрытия мини-аппы, и SDK молча отдаёт initData
* недельной давности, без единой ошибки.
*
* Цена — отказ входа: бэкенд принимает initData с `auth_date` не старше 30
* суток, и застрявшая копия рано или поздно пересекает порог, после чего
* логин отвечает «Invalid or expired Telegram authentication data».
*
* Поэтому спрашиваем ещё и `window.Telegram.WebApp.initData` — его пишет
* официальный мост Telegram (telegram-web-app.js, подключается в index.html),
* и он не завязан на кэш SDK. Какой из источников протух, зависит от платформы
* и способа открытия, поэтому берём не «первый доступный», а тот, у которого
* `auth_date` больше.
*/
export function getTelegramInitData(): string | null {
if (typeof window === 'undefined') return null;
const candidates = [fromTelegramBridge(), fromSdk()].filter((value): value is string =>
Boolean(value),
);
if (candidates.length === 0) return null;
// При равном или неразобранном auth_date побеждает мост: он ближе к
// источнику, чем кэш SDK.
return candidates.reduce((best, candidate) =>
authDateOf(candidate) > authDateOf(best) ? candidate : best,
);
}
function fromTelegramBridge(): string | null {
return window.Telegram?.WebApp?.initData || null;
}
function fromSdk(): string | null {
try {
return retrieveRawInitData() || null;
} catch {
// Вне Telegram параметров запуска нет — это не ошибка.
return null;
}
}
/** Метка времени выдачи initData; 0, если её не удалось разобрать. */
function authDateOf(initData: string): number {
try {
const raw = new URLSearchParams(initData).get('auth_date');
const parsed = Number(raw);
return raw && Number.isFinite(parsed) ? parsed : 0;
} catch {
return 0;
}
}