Emparejar pantallas con un código corto y un QR, sin contraseñas en la tele
Una pantalla de señalización suele vivir en un lobby, detrás de un mostrador o encima de una caja, y casi siempre se maneja con un mando a distancia. Pedir a quien la instala que escriba ahí el correo y la contraseña de la cuenta es lento, incómodo y deja la credencial más valiosa de la organización en un aparato compartido. En ChronoFlow una pantalla se une a la cuenta de otra forma: muestra un código corto y un QR, y alguien que ya inició sesión en el Controller lo reclama.
Este artículo cuenta cómo funciona ese emparejamiento por dentro: qué genera el servidor, qué comprueba antes de aceptar una pantalla y por qué el Player recibe su credencial una sola vez.
Tres actores, tres pasos
El mismo cliente Flutter funciona como Player (la pantalla que reproduce) o como Controller (la app o la web desde la que se administra); lo contamos en Controller y Player en un solo cliente. En el emparejamiento participan los dos, más la API:
- El Player abre una sesión. Envía su identificador de hardware, un nombre tentativo y la plataforma. La API responde con un código de emparejamiento y un secreto del dispositivo.
- El Controller reclama el código. La persona, con su sesión iniciada, escanea el QR o teclea el código, elige un nombre para la pantalla y, si quiere, un grupo.
- El Player recoge su credencial. Mientras espera, consulta el estado cada 2.5 segundos presentando su secreto. En cuanto la sesión está reclamada, recibe la credencial con la que operará como pantalla y pasa a reproducir.
Un código que se lee desde lejos
El código tiene seis caracteres y se muestra en dos bloques de tres, como 7K4 P9X. El alfabeto tiene 32 símbolos: letras mayúsculas y dígitos, sin 0, O, 1 ni I, que en una tele a tres metros se confunden. Eso da algo más de mil millones de combinaciones, suficientes para un código que vive dos minutos y cuyas consultas tienen límite de frecuencia por IP y por código.
Dos minutos es poco para teclear con calma, así que nadie tiene que pedir otro código: si caduca mientras la pantalla sigue esperando, la API lo rota en la siguiente consulta y entrega uno nuevo con el mismo secreto del dispositivo. En pantalla solo cambian el texto y el QR. Empezamos con cinco minutos. Con la rotación automática, acortarlo no costaba nada a quien instala y reducía el tiempo durante el que un código visible sirve para algo.
El código no basta: el secreto del dispositivo
El código está a la vista de cualquiera que pase delante de la pantalla, así que no puede ser lo único que separe a un curioso de la credencial del Player. Al crear la sesión, la API genera también un secreto aleatorio de 48 caracteres que solo viaja en esa respuesta. El servidor guarda únicamente su hash SHA-256 y el Player lo presenta en cada consulta.
Si alguien consulta un código sin el secreto correcto, recibe la misma respuesta que para un código inexistente o caducado: no se confirma que el código exista ni que esté pendiente. La comparación se hace en tiempo constante, para que tampoco se pueda deducir nada midiendo cuánto tarda la respuesta.
Reclamar: una transacción, varias comprobaciones
El Controller reclama el código con su sesión iniciada, y todo ocurre dentro de una transacción de base de datos:
- Una pantalla, un dueño. Si ese hardware ya está registrado en otra cuenta, el reclamo falla con un conflicto. Si ya está en la tuya, por ejemplo tras reinstalar la app, se reutiliza el Media Player existente en lugar de duplicarlo.
- Límite de pantallas del plan. Se comprueba con la fila del usuario bloqueada, así que dos reclamos simultáneos desde dos teléfonos no pueden pasarse juntos del límite.
- Solo grupos propios. La pantalla puede entrar directamente en un grupo, pero solo en uno que pertenezca a quien la reclama.
- Reintentos seguros. Si la red falla y el Controller repite el mismo reclamo, la segunda llamada devuelve el mismo resultado en lugar de un error.
En el plan gratuito, además, la cuenta recibe un aviso cuando le queda una pantalla libre y otro cuando llega al límite, para que el siguiente emparejamiento no sea una sorpresa.
La credencial se entrega exactamente una vez
Cuando el Player consulta una sesión reclamada, la API cambia su estado de reclamada a consumida en una sola operación atómica, y solo la petición que gana ese cambio recibe la credencial. Las consultas posteriores con el mismo código reciben «caducada». Si dos peticiones llegan a la vez, solo una se la lleva.
En ningún momento viaja al Player la contraseña del usuario: recibe una credencial propia, emitida para esa pantalla.
Una sesión pendiente por pantalla
Una tele que se reinicia o una app que se abre dos veces no deben dejar códigos huérfanos. Crear una sesión toma un bloqueo por identificador de hardware y caduca cualquier sesión pendiente anterior de esa misma pantalla, así que solo vale el último código mostrado. Un trabajo programado borra después las sesiones caducadas y consumidas, las pendientes viejas y las reclamadas que nadie recogió en 24 horas.
El QR es el mismo código
El QR no contiene un enlace de inicio de sesión ni un token: codifica el código de emparejamiento y nada más (en la app va con el prefijo chronoflow://pair/ para que el escáner lo reconozca). Fotografiar el QR equivale a fotografiar el código. Se genera en el propio dispositivo, sin llamar a ningún servicio externo, y por eso funciona igual en Android TV que en el navegador de una tele Samsung o LG, donde cada dependencia remota es un punto de fallo más (lo contamos en CORS en señalización).
Lo que descartamos
- Escribir la contraseña en la pantalla. Es lento con un mando, queda a la vista de quien mire y deja la credencial de la cuenta en un aparato compartido.
- Códigos de larga duración. Un código visible durante horas es una invitación. Con la rotación automática, la duración corta no le cuesta nada a quien instala.
- Un QR con un enlace o un token. Convierte una foto en una credencial. Con el código, el QR es solo un atajo para no teclear.
- Entregar la credencial a quien conozca el código. El código es público por diseño; lo que prueba que la petición viene de la pantalla correcta es el secreto que nunca se muestra.
Para seguir leyendo
Cómo un mismo cliente hace de Controller y de Player: Controller y Player en un solo cliente. El producto: ChronoFlow. Si estás diseñando el alta de dispositivos de tu propio producto: Servicios.