Add seed/Telegram login button and traffic usage indicator
New non-blocking login panel on the Home screen (seed backup/restore + Telegram magic-link via the bot deep-link, polled through the new backend endpoints) — uses its own popover instead of a full-screen Dialog so the burger menu stays clickable while it's open. VpnStats now shows a used/limit usage bar backed by a new useUsageStore. Also registers tauri-plugin-shell (needed to open the t.me deep-link) and threads an optional auth token from the app down through TunnelConfig to the proxy client (desktop + Android), for instances running --require-auth. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -140,3 +140,76 @@ export async function fetchNodes(): Promise<ServerNode[]> {
|
||||
const data = (await res.json()) as RawVpnNode[];
|
||||
return data.map(mapNode);
|
||||
}
|
||||
|
||||
/** Текущий JWT, если уже есть (для передачи прокси на `--require-auth` инстансах). */
|
||||
export function getCachedToken(): string | null {
|
||||
const cached = localStorage.getItem(TOKEN_KEY);
|
||||
return isTokenValid(cached) ? cached : null;
|
||||
}
|
||||
|
||||
/** Гарантирует, что seed/токен существуют (Ghost Protocol), и возвращает seed для бэкапа. */
|
||||
export async function getCurrentSeed(): Promise<string> {
|
||||
await ensureToken();
|
||||
const seed = localStorage.getItem(SEED_KEY);
|
||||
if (!seed) {
|
||||
// Юзер залогинен через Telegram (seed никогда не выдавался) — сгенерировать
|
||||
// отдельный seed поверх текущей сессии сервер сейчас не умеет, только через
|
||||
// новую анонимную регистрацию, что разлогинило бы текущий аккаунт.
|
||||
throw new Error("NO_SEED_FOR_ACCOUNT");
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
|
||||
/** Вход по чужому/сохранённому seed (например, с другого устройства). */
|
||||
export async function loginWithSeed(seed: string): Promise<void> {
|
||||
await loginSeed(seed);
|
||||
localStorage.setItem(SEED_KEY, seed);
|
||||
}
|
||||
|
||||
export interface TelegramLoginSession {
|
||||
authCode: string;
|
||||
deepLink: string;
|
||||
}
|
||||
|
||||
/** Создаёт ожидающую подтверждения сессию для входа через Telegram-бота (magic-link). */
|
||||
export async function startTelegramLogin(): Promise<TelegramLoginSession> {
|
||||
const res = await fetch(`${API_V1}/auth/telegram/session`, { method: "POST" });
|
||||
if (!res.ok) throw new Error(`telegram/session failed: ${res.status}`);
|
||||
const data = (await res.json()) as { auth_code: string; deep_link: string };
|
||||
return { authCode: data.auth_code, deepLink: data.deep_link };
|
||||
}
|
||||
|
||||
/** Опрашивает статус подтверждения; `true` — юзер подтвердил вход в боте. */
|
||||
export async function pollTelegramLogin(authCode: string): Promise<boolean> {
|
||||
const res = await fetch(`${API_V1}/auth/telegram/session/${authCode}`);
|
||||
if (res.status === 401 || res.status === 410) {
|
||||
throw new Error("TELEGRAM_LOGIN_EXPIRED");
|
||||
}
|
||||
if (!res.ok) throw new Error(`telegram/session poll failed: ${res.status}`);
|
||||
const data = (await res.json()) as { status: string; token?: string };
|
||||
if (data.status === "success" && data.token) {
|
||||
localStorage.setItem(TOKEN_KEY, data.token);
|
||||
localStorage.removeItem(SEED_KEY);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export interface UsageInfo {
|
||||
usedBytes: number;
|
||||
limitBytes: number | null;
|
||||
}
|
||||
|
||||
/** Текущий расход/лимит трафика юзера — для индикатора на `VpnStats`. */
|
||||
export async function fetchUsage(): Promise<UsageInfo> {
|
||||
const token = await ensureToken();
|
||||
const res = await fetch(`${API_V1}/users/me`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
if (!res.ok) throw new Error(`GET /users/me failed: ${res.status}`);
|
||||
const data = (await res.json()) as {
|
||||
data_used_bytes: number;
|
||||
data_limit_bytes: number | null;
|
||||
};
|
||||
return { usedBytes: data.data_used_bytes, limitBytes: data.data_limit_bytes };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user