Mapping - Los clips salian del reves: mapper.js activaba UNPACK_FLIP_Y_WEBGL, pero el modelo va con origen arriba-izquierda y texImage2D ya sube la primera fila en t=0, asi que el flip la mandaba al final. Comprobado renderizando el mapper real en Chromium headless con una fuente mitad roja / mitad azul. - projectM se puede usar YA en una capa: los .milk de data/presets-projectm se traducen a Butterchurn en el navegador al elegirlos (milkdrop-preset- converter). La capa MilkDrop gana 'biblioteca' (butter | projectm) sin cambiar su firma, para no recrear el contexto WebGL al cambiar de una a otra. Medido: 100/100 presets de una muestra convierten, 84/84 de los que llevan shaders warp/comp; ~7 ms por preset. - Cada capa tiene su pestana arriba y su propia vista, y '+ CAPA' crea una y entra en ella: con varias capas, ir y volver a MAPPING no era viable. - Dos capas MilkDrop sin preset ya no salen identicas (cogian el indice 0): cada instancia elige uno al azar y lo escribe en el estado. - Una capa nueva ya no nace en la fuente "motor", que es el lienzo del motor activo y hacia que dos capas ensenaran lo mismo. Galeria de visuales - scripts/catalogar-visuales.py: ficha de cada clip (pelicula, personajes, duracion) y, sobre todo, si es una silueta de verdad y cuanta figura tiene. Distingue silueta de corte crudo por el negro puro del fondo: 0,63-0,90 frente a 0,04-0,06, sin zona gris. - El panel lista los clips agrupados por pelicula, con nombre legible y aviso de los que casi no tienen figura, en vez del nombre del archivo. - Soporte de siluetas con canal alfa (.webm VP9): transparencia de verdad, sin recorte por luminancia. El shader del mapper ya la respeta. Documentacion - docs/visuales.md nuevo; pendiente.md al dia con lo hecho y lo que queda. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4.2 KiB
Seguridad
FOSFENO es un aparato de directo, no un servicio en internet. Está pensado para una red local: tú, tu móvil y el proyector. Esta página cuenta qué asume el diseño, qué pasa si la red no es de fiar, y cómo cerrarlo.
El modelo de amenaza, en una frase
Cualquiera que alcance http://<ip-de-fosfeno>/ manda sobre las visuales.
Por defecto no hay contraseña: es lo cómodo para casa, un ensayo o una red
tuya, y es como funcionó desde el principio.
Eso está bien en tu salón. En la wifi de un bar o de un festival significa que un desconocido puede:
- Apagar o reiniciar el equipo en mitad de la sesión.
- Cambiar de motor, de preset y de mapping.
- Ejecutar código en el escenario, porque el editor de Hydra/GLSL es precisamente eso, y el navegador del kiosko arranca con permiso automático de cámara y micrófono.
- Llenarte la tarjeta subiendo archivos a la galería.
No es un fallo escondido: es la consecuencia de no pedir credenciales. La solución está abajo y son dos líneas de configuración.
La clave compartida
En config.json:
"auth": {
"token": "loquesea-largo-y-tuyo"
}
O sin tocar el archivo, por variable de entorno:
FOSFENO_TOKEN=loquesea-largo-y-tuyo ./fosfeno
Con la clave puesta:
- El código QR del proyector ya la lleva dentro. Escaneas y entras, igual que siempre. No hay que teclear nada.
- Quien solo conozca la IP no se conecta: el WebSocket rechaza la conexión, así que no puede ni mirar el estado ni mandar órdenes.
- Las subidas a la galería también la piden.
- El escenario la recibe del propio servidor al abrirse. No hay nada que configurar en el navegador.
La contrapartida: si escribes la dirección a mano tendrás que añadir
?k=tu-clave al final. Por eso el QR es el camino cómodo.
Con
tokenvacío (el valor de fábrica) todo funciona exactamente como antes. Actívala cuando pinches fuera de casa.
Lo que ya está cerrado
Estas no dependen de que actives nada:
| Path traversal | Las rutas de archivos (/panel, /stage, /lib, /data, /pm/variantes) resuelven y comprueban que no salen de su carpeta. Probado con ../, %2e%2e%2f, doble codificación y rutas absolutas |
| Nombres de archivo subidos | Pasan por secure_filename y una lista blanca de extensiones. No se puede escribir fuera de data/videos ni subir un .sh |
| Inyección de comandos | Ningún shell=True, ningún os.system. Todos los procesos se lanzan con lista de argumentos |
| Rutas de presets de projectM | La categoría y el visual vienen del panel, así que se validan contra la carpeta de presets antes de usarse |
| XSS en el panel | Los nombres de clips, capas y favoritos se pintan con textContent, nunca con innerHTML |
| CORS | El WebSocket solo acepta su mismo origen. Antes admitía cualquiera, así que una web abierta en el móvil de alguien de la sala podía mandar órdenes |
| Tamaño de subida | 512 MB por archivo (antes 4 GB, suficiente para llenar una microSD en tres peticiones) |
| Payloads del WebSocket | Los ajustes se filtran por lista blanca de claves y las capas del mapping se sanean antes de guardarse, así que no se puede meter basura en el estado ni en data/mapping.json |
Lo que NO deberías hacer
- No lo expongas a internet. Nada de abrir el puerto 80 en el router ni ponerle un túnel. No está pensado para eso y la clave compartida no es autenticación seria.
- No dejes el apagado remoto a mano de una red pública sin clave. El
instalador da permiso
sudosin contraseña pararebootypoweroff(install.sh), que es lo que hace que el botón del panel funcione. - No pongas datos personales en
data/videos. Cualquiera que entre al panel puede listarlos y reproducirlos.
Lo que no se sube al repositorio
.gitignore deja fuera lo de cada instalación: .venv/, *.log (el log del
servidor lleva IPs), data/mapping.json, data/pm-favoritos.json,
data/videos/* y data/presets-projectm/. En el repo solo van código,
documentación y los presets de fábrica.
Si encuentras algo
Es un proyecto pequeño de un hacklab: abre una incidencia en el Gitea del proyecto contando qué has visto y cómo reproducirlo.