Changelogs

El enlace de activación vuelve a ser alfanumérico; avisar a qué correo se envió

15 de julio de 2026 a las 17:34

adevopg · 8c85cf2

Dos cosas que el port de Django cambió sin querer: - El hash de activación se generaba con `randomBytes(16).toString('hex')`: 32 caracteres, sí, pero solo `0-9a-f`. El original era `get_random_string(32)`, alfanumérico con mayúsculas y minúsculas (`?act=P4JHQDJey2jJDnEBnqUePI5O2qEFB1`). - El aviso de cuenta creada era un genérico «Revisa tu correo», mientras que el original decía qué cuenta se creó y a qué dirección fue el enlace. Se recupera el formato de dos líneas (con id `create-response`, como el original). El muestreo por rechazo del token de seguridad se sube a `lib/random-token.ts` y lo comparten los dos generadores, que solo se diferencian en el alfabeto: letras para el token que se teclea a mano, alfanumérico para el hash de la URL. Verificado con 100.000 hashes: todos casan /^[A-Za-z0-9]{32}$/, salen los 62 caracteres y la desviación por carácter se queda en 1,3% (ruido).




El token de seguridad son 6 letras al azar, no base64url sesgado

15 de julio de 2026 a las 17:11

adevopg · 6e4a123

El token se generaba con `randomBytes(4).toString('base64url').slice(0, 6)`, portado tal cual del Django original (`secrets.token_urlsafe(4)[:6]`), y tenía dos taras para un código que se lee y se teclea desde un correo: - Metía `-` y `_`. - 4 bytes son 32 bits, pero 6 caracteres base64 codifican 36: al último solo le llegaban 2 bits reales, así que SIEMPRE terminaba en A, Q, g o w (comprobado sobre 20.000 tokens: 4 valores distintos en esa posición). Ahora son 6 letras A-Z/a-z uniformes, con muestreo por rechazo porque 256 no es múltiplo de 52 y `byte % 52` favorecería a las primeras letras. Verificado con 300.000 tokens: todos casan /^[A-Za-z]{6}$/, las 52 letras aparecen en la última posición y la desviación por letra se queda en el 1,4% (ruido).




El token de seguridad caducado ya no vale; traducir 2 errores que faltaban

15 de julio de 2026 a las 17:03

adevopg · 75e4cee

checkSecurityToken guardaba expires_at pero NO lo comprobaba: un token caducado seguía siendo válido para regalos y servicios. Se comprueba en SQL (`expires_at > NOW()`) y no en JS, para que los dos lados de la comparación sean hora del servidor: expires_at se inserta como Date de JS y compararlo contra Date.now() dependería de que Node y MySQL tuvieran la misma zona. Además faltaban `errors.notAuthenticated` e `invalidRequest` en el namespace Store (ES y EN): si se caducaba la sesión, send-gift decía «Ha ocurrido un error» en vez de pedir que vuelvas a iniciar sesión — justo el mensaje que hace pensar que el botón sigue roto.




Mostrar los errores de send-gift: el tema los dejaba invisibles

15 de julio de 2026 a las 17:03

adevopg · 47b5a2a

El botón «Mostrar regalos» parecía no hacer nada: setFormError se llamaba bien, pero el tema deja `.alert-message` con display:none esperando que la rellene y la revele el JS antiguo (jQuery), que ya no existe. La caja se pintaba y no se veía. Se fuerza el display desde React, como el resto de formularios. De paso, `.modal-content` estaba definida en globals.css Y en theme.css. Como theme.css se importa el último (a propósito, para ganarle al preflight de Tailwind), ganaba él a igual especificidad y el bloque de globals.css era código muerto: el modal de la tienda salía como hoja pegada al fondo con borde gris en vez de tarjeta centrada dorada. Se acota a `.modal-div .modal-content` para ganar por especificidad y no por orden.




El CSS del tema entra por el build en vez de un <link> desde public/

15 de julio de 2026 a las 16:20

adevopg · 97ccb8a

Antes: <link href="/ns-themes/.../nightspire-style.css?v=2"> en el <head>. Una peticion aparte, sin minificar y con cache invalidada a mano con ?v=2. Ahora: app/theme.css, importado al FINAL de globals.css. Next lo compila, minifica y le pone hash de contenido; se sirve con cache immutable y hay una hoja de estilo menos (4 -> 3). ⚠ El @import va el ULTIMO y no es cosmético: el tema se diseñó contra los defaults del navegador y el preflight de Tailwind los pisa (box-sizing, alturas). Antes ganaba la cascada por cargarse el último en el <head>; ahora gana por ser el último import. Si sube de sitio, el diseño se rompe. Las url() pasan a ABSOLUTAS (/ns-themes/ns-ryu/...). Los assets siguen en public/, y así el compilador no intenta resolverlos: el @font-face declara .eot/.otf/.ttf que NO existen (solo hay .woff) y con rutas relativas el build fallaría. Verificado: los 6 páginas dan exactamente el mismo alto que antes (8159, 1356, 2645, 1356, 2221, 2349 px) con la misma fuente y colores, y el input del login sigue en box-sizing:content-box — que es justo donde el preflight rompía. Ojo: el md5 de las capturas NO sirve para comparar, porque la cabecera lleva un vídeo y cada captura pilla un fotograma distinto.





SÍGUENOS EN