Cliente web de Telegram en React + GramJS, fork de evgeny-nadymov/telegram-react.
Demo: tg.todosobreall.tech
⚠️ Experimental. No es un cliente oficial. Para uso diario, telegram.org/apps.
- Por qué este fork
- Qué añade
- Estado de funcionalidades
- Arquitectura
- Despliegue local
- Despliegue en producción
- Contribuir
- Seguridad
- Hoja de ruta
- Créditos y licencia
El upstream de evgeny-nadymov estaba congelado en la capa 127 de MTProto y faltaban features de Telegram modernas (encuestas con formato, blockquote, Instant View con caché, fixes de llamadas). Este fork pone al día el cliente sobre capa 198 con GramJS 2.26.x, sin perder compatibilidad con la base original.
Objetivo principal: tener un cliente web autoalojable, auditable y centrado en privacidad — sin telemetría, sin tracking de terceros, sirviendo desde tu propia infraestructura.
- Blockquote (
messageEntityBlockquote, soporte decollapsed). - Encuestas enriquecidas (
PollAnswercontext_entities). - Instant View con caché ("really instant" de Telegram 6.9.0): el
wp.cachedPagese cachea al traducirMessageMediaWebPage;_getWebPageInstantViewsirve desde caché antes de pedir red. - Envío de voto (
messages.SendVote) y cierre de encuestas (stopPoll). - Sesiones activas (Devices):
account.GetAuthorizations,ResetAuthorization,ResetAuthorizations.
Tres fixes críticos sobre el flujo:
| Fix | Archivo | Descripción |
|---|---|---|
| ICE candidates pendientes | CallController.js:_tryBuildRemoteSdp |
Antes se descartaban tras setRemoteDescription. Ahora se añaden con splice(0) + try/catch por candidato. |
| g_a_hash anti-MITM | CallController.js:_onCallConfirmed |
Verificación SHA-256 del g_a recibido vs g_a_hash almacenado. Aborta con phone.DiscardCall si no coincide. |
| Timeout signaling queue | CallController.js |
Timer de 10s si _authKey no llega; vacía cola y limpia. |
Pendiente: race condition del DH en requestCall, fallback ICE con TURN real (hoy solo STUN de Google → ~30% no conecta tras NAT simétrico), vídeo y group calls.
- 8 skins de tema con estilos por skin.
- Búsqueda de chats funcional (
getTopChats,searchChats,addRecentlyFoundChat). - Tutorial de onboarding de 8 pasos (
TutorialDialog.js), persistente en localStorage. - Hotkey Escape para cerrar diálogos.
- CHANGELOG por sesión de desarrollo en
CHANGELOG.md.
| Función | Estado | Notas |
|---|---|---|
| Login (teléfono + 2FA) | ✅ | |
| Mensajes de texto | ✅ | |
| Búsqueda de chats | ✅ | |
| Encuestas (votar + cerrar) | ✅ | |
| Blockquote | ✅ | Soporta collapsed |
| Instant View con caché | ✅ | AMP no se beneficia (iframe externo) |
| Sesiones activas | ✅ | |
| Llamadas de voz 1-a-1 | Conecta si ambos extremos tienen ruta directa o STUN basta; falla tras NAT simétrico | |
| Videollamadas | ❌ | Código existe, no verificado |
| Llamadas grupales | ❌ | No soportado |
| Editar perfil | ❌ | account.UpdateProfile/UpdateUsername pendiente |
| Mensajes de voz | ❌ | Pendiente |
| Forum topics | ❌ | Pendiente |
| Búsqueda dentro de chat | ❓ | Pendiente verificar (messages.Search) |
┌─────────────────────────────────────────────────────────┐
│ Navegador del usuario │
├─────────────────────────────────────────────────────────┤
│ React UI (src/) │
│ └─ TelegramApp.js │
│ └─ Componentes (Calls, ColumnLeft, Tile, etc.) │
│ │
│ Controllers (src/Controllers/) │
│ ├─ ApplicationStore.js — estado global │
│ ├─ CallController.js — WebRTC + DH + tgcalls │
│ └─ GramJsController.js — bridge MTProto (caller side)│
│ │
│ GramJS (node_modules/gramjs) │
│ └─ MTProto + serialización TL (capa 198) │
│ │
│ Service Worker (sw-precache) │
│ └─ Caché de assets para uso offline │
└─────────────────────────────────────────────────────────┘
│
│ WSS (MTProto sobre WebSocket)
▼
Telegram DCs
Componentes clave de llamadas:
src/Controllers/CallController.js— máquina de estados, Diffie-Hellman, WebRTC.src/lib/TgCallsSignaling.js— AES-CTR, gzip, parsing/construcción SDP.src/Utils/GramJs/UpdateTranslator.js— traduce updates MTProto a formato interno.src/Components/Calls/IncomingCall.js/ActiveCall.js— overlays UI.
Requisitos: Node.js 16+ y npm.
git clone https://github.com/ComunidadTelebots/telegram-react.git
cd telegram-react
npm install
cp node_modules/tdweb/dist/* public/Configuración — crea .env.local (en .gitignore, no se versiona) con credenciales de my.telegram.org/apps:
REACT_APP_TELEGRAM_API_ID=tu_api_id
REACT_APP_TELEGRAM_API_HASH=tu_api_hash
Aviso: en clientes web el
api_hashsiempre acaba en el bundle JS y es extraíble. Usa una app dedicada a este despliegue, no la misma que uses para otros proyectos. Si Telegram detecta abuso, podría revocarla.
Arrancar:
npm start # http://localhost:3000
npm run build # build de producción en build/Build estático sirvible por cualquier servidor (nginx, Apache, Caddy):
REACT_APP_TELEGRAM_API_ID=... REACT_APP_TELEGRAM_API_HASH=... npm run buildImportante: si vas a servir desde la raíz del dominio, quita o ajusta la línea
"homepage"depackage.jsonantes del build. De lo contrario el service worker pedirá assets desde/telegram-react/...y devolverá 404.
Ejemplo docker-compose.yml (nginx + Traefik):
services:
tg-web:
image: nginx:alpine
restart: unless-stopped
volumes:
- ./build:/usr/share/nginx/html:ro
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.tg.rule=Host(`tg.example.com`)"
- "traefik.http.routers.tg.entrypoints=websecure"
- "traefik.http.routers.tg.tls.certresolver=letsencrypt"
networks:
traefik:
external: trueHeaders de seguridad recomendados en nginx:
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(self), camera=(self)" always;- Abre una issue describiendo qué quieres tocar (bug o feature).
- Fork + branch desde
master. - Sigue el estilo del código existente (ESLint config heredada del upstream).
- Si tocas el flujo de llamadas, prueba con un cliente oficial (Android/iOS) en ambas direcciones (caller y callee) — son rutas distintas.
- PR contra
mastercon descripción de qué cambia y cómo se ha probado.
Actualiza el CHANGELOG.md con tu cambio en una sección nueva con fecha.
Reportar vulnerabilidades en privado — no abrir issue público:
- Telegram: @TodoSobreAllTech
Mejores prácticas si lo autoalojas:
- Sirve siempre por HTTPS (WebRTC y
getUserMedialo requieren). - Aplica los headers de seguridad de arriba.
- Mantén
.env*fuera del repo (.gitignore). - Considera Content Security Policy estricta (ojo: WebRTC necesita
connect-srca los DCs de Telegram).
Corto plazo:
- Race condition DH en
requestCall. - Fallback ICE con TURN real desde
phoneCall.connections. - Editar perfil (
account.UpdateProfile). - Verificar búsqueda dentro de chat (
messages.Search).
Medio plazo:
- Videollamadas (verificación + pruebas).
- Mensajes de voz (grabación + envío).
- Forum topics.
- Migrar service worker a Workbox (
sw-precachedeprecated).
Largo plazo:
- Llamadas grupales (requiere mediasoup/SFU, esfuerzo alto).
- Base original: evgeny-nadymov/telegram-react.
- Mantenedor del fork: ComunidadTelebots — @TodoSobreAllTech.
- Librería MTProto: GramJS.
Licencia: GPL-3.0, heredada del upstream.