telegram free connection

This commit is contained in:
2026-05-02 18:11:05 +07:00
parent f836da06d5
commit 6de8968f11
20 changed files with 428 additions and 114 deletions
+187
View File
@@ -0,0 +1,187 @@
import { useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useVpnStore } from "@/store/useVpnStore";
import { useSettingsStore } from "@/store/useSettingsStore";
import { TunnelConfig, startVpn, stopVpn, launchApp } from "vpn-plugin";
import { Button } from "@/components/ui/button";
import { ShieldAlert, Loader2, Send } from "lucide-react";
import { motion, AnimatePresence } from "framer-motion";
import { isDesktop } from "@/lib/platform";
export function TelegramWeb() {
const { t } = useTranslation();
const { status, setStatus } = useVpnStore();
const { killSwitch, excludedDomains } = useSettingsStore();
const [sessionRequested, setSessionRequested] = useState(false);
const [errorMsg, setErrorMsg] = useState("");
const handleStopSession = async () => {
setSessionRequested(false);
try {
await stopVpn();
} catch (e) {
console.error("Stop VPN error:", e);
}
};
// Следим за возвратом в наше приложение
useEffect(() => {
const handleVisibilityChange = () => {
// Если мы запросили сессию и юзер вернулся в приложение (документ стал видимым)
if (document.visibilityState === "visible" && sessionRequested) {
console.log(
"Anti-Abuse: User returned to app, killing Telegram tunnel.",
);
handleStopSession();
}
};
document.addEventListener("visibilitychange", handleVisibilityChange);
return () =>
document.removeEventListener("visibilitychange", handleVisibilityChange);
}, [sessionRequested]);
const handleStartSession = async () => {
setErrorMsg("");
setSessionRequested(true);
// Пакеты официальных клиентов Telegram
const tgPackages = [
"org.telegram.messenger",
"org.telegram.messenger.web",
"org.telegram.plus",
"org.thunderdog.challegram",
];
if (status !== "connected") {
setStatus("connecting");
try {
const config: TunnelConfig = {
address: "10.0.0.1",
prefix: 24,
dns: "10.0.0.2",
mtu: 1380,
killswitchEnabled: true, // Всегда киллсвитч
excludedApps: [], // Игнорируем исключения
excludedDomains,
allowedApps: tgPackages, // УКАЗЫВАЕМ, ЧТО ТОЛЬКО ЭТИ ПРИЛОЖЕНИЯ ИДУТ В VPN
};
await startVpn(config, "147.45.43.70", 443);
} catch (error) {
setStatus("idle");
setSessionRequested(false);
setErrorMsg("Не удалось установить соединение.");
return;
}
}
// Пытаемся запустить Telegram через Intent
let launched = false;
for (const pkg of tgPackages) {
try {
await launchApp(pkg);
launched = true;
break; // Если успешно, прерываем цикл
} catch (e) {
console.warn(`App ${pkg} not found`);
}
}
if (!launched) {
setErrorMsg("Telegram не установлен на этом устройстве.");
handleStopSession();
}
};
// Блокируем на ПК
if (isDesktop) {
return (
<div className="w-full h-[calc(100vh-4rem)] flex flex-col p-6 items-center justify-center text-center max-w-sm mx-auto">
<div className="size-24 bg-primary/10 rounded-full flex items-center justify-center mb-6">
<ShieldAlert className="size-12 text-primary opacity-80" />
</div>
<h2 className="text-2xl font-black uppercase tracking-tighter">
Только для мобильных
</h2>
<p className="text-sm text-muted-foreground mt-4 leading-relaxed">
Безопасная сессия с инкапсуляцией трафика требует запуска нативного
приложения Telegram. Пожалуйста, откройте этот раздел со своего
смартфона.
</p>
</div>
);
}
const isSessionActive = sessionRequested && status === "connected";
return (
<div className="w-full h-[calc(100vh-4rem)] flex flex-col p-6 items-center justify-center text-center">
<AnimatePresence mode="wait">
{!isSessionActive ? (
<motion.div key="intro" className="max-w-sm space-y-6">
<div className="mx-auto size-24 bg-primary/10 rounded-full flex items-center justify-center relative border border-primary/20">
<Send className="size-10 text-primary drop-shadow-[0_0_15px_rgba(130,0,219,0.5)] relative right-1" />
<div className="absolute -bottom-2 bg-primary text-black text-[10px] font-black px-2 py-1 rounded-md uppercase">
Allow-List
</div>
</div>
<div className="space-y-2">
<h2 className="text-2xl font-black uppercase italic tracking-tighter">
Защита клиента
</h2>
<p className="text-sm text-muted-foreground leading-relaxed">
Трафик телефона блокируется. Доступ в сеть получает{" "}
<b>только приложение Telegram</b>. При закрытии мессенджера
туннель немедленно разрывается.
</p>
</div>
{errorMsg && (
<p className="text-xs font-bold text-destructive uppercase tracking-widest">
{errorMsg}
</p>
)}
<Button
onClick={handleStartSession}
disabled={status === "connecting"}
className="w-full h-14 rounded-2xl font-black tracking-widest"
>
{status === "connecting" ? (
<Loader2 className="animate-spin" />
) : (
"ОТКРЫТЬ TELEGRAM"
)}
</Button>
</motion.div>
) : (
<motion.div key="active" className="space-y-8 max-w-sm">
<div className="space-y-4">
<div className="text-5xl font-mono font-black text-primary tracking-tighter animate-pulse">
ACTIVE
</div>
<div className="flex flex-col items-center gap-2">
<p className="text-primary uppercase text-[10px] font-black tracking-[0.3em]">
Сессия привязана к приложению
</p>
<span className="px-3 py-2 bg-white/5 border border-white/10 rounded-xl text-xs text-muted-foreground leading-relaxed">
Telegram запущен в защищенном режиме. Если вы читаете этот
текст, значит вы свернули Telegram и туннель будет отключен.
</span>
</div>
</div>
<Button
variant="outline"
onClick={handleStopSession}
className="gap-2 text-destructive border-destructive hover:bg-destructive hover:text-white w-full h-12 rounded-xl transition-all"
>
СБРОСИТЬ СОЕДИНЕНИЕ
</Button>
</motion.div>
)}
</AnimatePresence>
</div>
);
}