Pregunta
Terminal SSH: ¿cómo se conecta el navegador al Local Agent en localhost:5050 y cómo se establece la sesión SSH vía WebSocket ws/terminal? Protocolo crearack:// y persistencia de sesiones.
Respuesta corta
El navegador no habla SSH directamente. Abre un WebSocket contra el Local Agent en 127.0.0.1:5050, y es el Agente —que corre dentro de la LAN del cliente— quien abre la sesión SSH real contra el dispositivo. El Agente actúa de puente cifrado: transporta tus teclas al dispositivo y la salida de vuelta al navegador.
El flujo paso a paso
- Detección + auth local: el frontend confirma que el Agente está vivo (fetch a
/info) y obtiene el token local del SaaS para autorizar la API local (ver la página de credenciales del Local Agent). - Apertura del WebSocket:
ws://127.0.0.1:5050/ws/terminal/{client_id}. Con el Agente vinculado a un SaaS, el primer mensaje debe ser{"action":"auth","token":<token_local>}(la UI lo recibe del SaaS porpostMessage SET_AUTH_TOKEN). Sin token válido → el Agente cierra con código 4401 (terminal/agent/routes/terminal.py:255-263). - Conexión SSH:
{"action":"connect", "device_id"|"profile_id": ...}. El Agente resuelve las credenciales server-side con su JWT (R3) —fetch_device_credentials/fetch_profile_credentials(terminal.py:315-330) — abreasyncsshcon host-key TOFU y responde"Tunnel Established!". El navegador nunca ve la contraseña. - Interacción: cada tecla viaja como
{"action":"data", ...}al PTY del dispositivo; la salida vuelve por el mismo WebSocket como{"type":"output"}.
Persistencia de sesiones (reattach)
Al navegar entre páginas el WebSocket se cae, pero la sesión SSH sobrevive. El Agente conserva el puente en memoria (ACTIVE_BRIDGES) y solo pone bridge.websocket = None (log: “Client decoupled (SSH session persists)”, terminal.py:342). Al reconectar con el mismo client_id, si el SSH sigue vivo, el Agente reproduce el output_buffer (te devuelve lo que salió mientras no mirabas) y responde "Tunnel Established!" (terminal.py:265-278). Si el SSH murió mientras estabas desconectado, limpia el puente obsoleto y abre uno nuevo.
El protocolo crearack://
Sí existe (el draft anterior decía que no; es incorrecto). El instalador registra crearack como protocolo URL de Windows en el registro: HKCU\SOFTWARE\Classes\crearack con comando "CreaRackAgent.exe" "%1" (_register_protocol_handler, terminal/agent/core/installer.py:217). Así, un enlace crearack://… desde el navegador lanza o enfoca el Agente local (deep-link), sin depender de que el usuario lo abra a mano.
Seguridad del canal
- La API local exige
Authorization: Bearer <token_local>salvo rutas de bootstrap; el WS de la consola valida el token en el primer mensaje (close 4401). Cierra el DNS-rebinding/CSRF (Raíz 3 de la Auditoría Suprema). - Las credenciales del dispositivo nunca las teclea ni relé el navegador: el Agente las obtiene server-side por
device_id/profile_id(R3). Cifradas en reposo (Fernet en el SaaS, DPAPI en el Agente). - Host-key TOFU (
network/host_keys.py): graba la clave del dispositivo en la 1ª conexión y rechaza si cambia (detección de MITM).
Véase también
- [[concept—general—como-obtiene-el-local-agent-sus-credenciales-de-vi]]
- [[concept—general—como-detecta-el-frontend-si-el-local-agent-esta-co]]
Referenciado desde
- ¿Cómo detecta el frontend si el Local Agent está corriendo? ¿Cómo se construye la URL del agente (localhost:5050) y qué CORS/orígenes acepta el agente local?
- ¿Cómo obtiene el Local Agent sus credenciales de vinculación con el SaaS al instalarse? ¿El .exe descargado desde la app lleva un token embebido? ¿Qué es el token local 'not authorized' y cómo se auto
- Modelo de despliegue del Local Agent de CreaRack: ¿cada usuario necesita un Agente en SU propia máquina (el navegador sondea 127.0.0.1:5050 local), o hay un modelo de Agente CENTRAL/compartido en un s