Librería con listas, recomendaciones, descarga anticipada, app instalable con lectura offline y seguridad para exponerlo a internet

- Historial pasa a Librería: pestañas Leyendo, Siguiendo, Terminados, En el dispositivo y listas propias (Favoritos, Pendientes, Abandonados por defecto)
- Recomendaciones en el inicio según tus géneros más leídos (populares de MangaDex)
- Descarga anticipada de los N capítulos siguientes (opcionalmente en HD) al pasar la mitad de uno
- PWA: manifest, iconos y service worker; capítulos guardados en el dispositivo para leer sin conexión, progreso offline sincronizado después
- Seguridad: baneo de IP tras 6 intentos fallidos (configurable), IP real detrás de proxies de confianza, CSP y cabeceras, cookie Secure/HSTS en HTTPS, login sin diferencias de tiempo, registro cerrado por defecto, contraseñas de 8+, protección SSRF en el proxy de imágenes, errores 500 genéricos
- Ajustes: sección Seguridad con IPs bloqueadas, intentos recientes y la IP vista por el servidor
- LeerCapitulo: reintentos ante caídas (522/5xx), copia anterior si sigue caído y mensaje claro

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-01 07:52:13 -06:00
co-authored by Claude Opus 5.5
parent 9086896a89
commit d3e196a2f3
16 changed files with 931 additions and 59 deletions
+28
View File
@@ -40,6 +40,17 @@ Lector web de manga autoalojado, con las dos fuentes de
(capítulo y página en curso, siguientes, tiempo restante, errores con "Reintentar", "Detener"),
recortes y portadas pendientes, y debajo la biblioteca descargada con su tamaño; todo en tarjetas
verticales con portada, como el historial.
- **Librería** (antes "Historial"): pestañas Leyendo, Siguiendo, Terminados, En el dispositivo y
listas propias (Favoritos, Pendientes, Abandonados y las que crees). Desde la ficha, el botón
"Listas" añade o quita el manga de cada lista.
- **Recomendado para ti** (inicio): populares de MangaDex con capítulos en tu idioma dentro de tus 3
géneros más leídos, sin lo que ya tienes en la librería.
- **Descarga anticipada** (Ajustes): al pasar la mitad de un capítulo, el servidor baja los N
siguientes (por defecto 2) a la copia local y, si se marca, los reescala a HD.
- **App instalable y lectura sin conexión**: manifest + service worker. En la ficha, "En este
dispositivo" guarda capítulos (páginas incluidas) en el navegador para leerlos sin internet; el
progreso leído sin red se envía al volver. **Requiere HTTPS** (o `localhost`): por `http://IP:puerto`
el navegador no permite service workers. Por ejemplo `tailscale serve` o un proxy con certificado.
- **Estadísticas**: rachas, capítulos y páginas por semana, calendario de actividad, géneros
favoritos y lo más leído.
- Las imágenes pasan por el servidor (`/api/img`), solo con URLs firmadas por él (clave en `data/secret`).
@@ -59,6 +70,23 @@ Sin `.env` arranca igual: puerto 3352 en todas las interfaces y descargas en `./
El primer usuario puede registrarse siempre; después el registro queda cerrado salvo
`ALLOW_SIGNUP=true` en `.env`.
## Exponerlo a internet
- **Pon HTTPS delante** (Caddy, Nginx, Cloudflare Tunnel o `tailscale funnel`): sin HTTPS la contraseña
y la cookie viajan en claro. Con HTTPS la cookie lleva `Secure` y se envía HSTS.
- Con un proxy inverso, define `REAL_IP_HEADER` en `.env` (`x-forwarded-for` en Caddy/Nginx,
`cf-connecting-ip` en Cloudflare) para que el baneo vea la IP real. Solo se cree esa cabecera si la
conexión llega desde una IP privada (el proxy), así que desde internet no se puede falsificar.
- **Baneo de IP**: 6 intentos fallidos (contraseña incorrecta, registro con el registro cerrado,
contraseña actual incorrecta) en 60 min bloquean la IP 24 h para toda la web. Ajustable con
`BAN_MAX_FAILS`, `BAN_WINDOW_MIN`, `BAN_HOURS`; red local, loopback y Tailscale nunca se bloquean.
En Ajustes se ven las IPs bloqueadas y se pueden desbloquear.
- Registro cerrado por defecto (`ALLOW_SIGNUP=false`); contraseñas de 8+ caracteres; cambiar la
contraseña cierra las demás sesiones.
- Cabeceras: CSP estricta (sin scripts en línea), `X-Frame-Options: DENY`, `nosniff`, `Referrer-Policy`.
- El proxy de imágenes solo descarga URLs firmadas por el servidor y nunca hacia IPs privadas
(comprobado también en cada redirección). Los errores internos no se muestran al cliente.
## Qué guardar / mover a otro servidor
| Qué | Dónde | Contenido |