FOSFENO/docs/seguridad.md
hacklab f017246f0e Capas independientes, projectM en el mapping y catalogo de la galeria
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>
2026-08-02 14:56:01 +02:00

94 lines
4.2 KiB
Markdown

# 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`:
```json
"auth": {
"token": "loquesea-largo-y-tuyo"
}
```
O sin tocar el archivo, por variable de entorno:
```bash
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 `token` vací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 `sudo` sin contraseña para `reboot` y `poweroff`
(`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.