Resolver error “Invalid host header” al usar ngrok con vue-cli

Si queremos probar la aplicación que estamos desarrollando con vue-cli a través de ngrok puede que nos encontremos con el error “Invalid host header” si tenemos configurado el proyecto con un nombre de dominio que no sea localhost.

En estos casos hay que lanzar ngrok especificando el host header, por ejemplo:

ngrok http 8081 -host-header="dev.customer:8081"

Cambiar el padre de un elemento mediante media queries (más o menos)

En HTML los elementos se muestran en pantalla en el orden en el que aparecen en el código fuente. En este ejemplo:

<div class="grupo1">
<div class="e1g1">Elemento 1 grupo 1</div>
<div class="e2g1">Elemento 2 grupo 1</div>
</div>
<div class="grupo2">
<div class="e1g2">Elemento 1 grupo 2</div>
</div>

el grupo 1 se mostrará antes que el grupo 2.

Antes de que existieran CSS Flex y CSS Grid la única forma de poder alterar ese orden era meter en el código una copia del grupo 2 con otra clase y mediante media queries mostrar la copia y ocultar el original al cambiar de ancho. Funcionaba, pero no era demasiado elegante.

Gracias a la magia de CSS Flex y CSS Grid resulta muy sencillo invertir el orden en el que se muestran los bloques, y podemos incluso definirlo visualmente con las áreas de CSS Grid.

Sin embargo hay una cosa que aún no podemos hacer solo con CSS y para lo que necesitaremos JS (de ahí el más o menos del título). ¿Qué pasa si queremos que a partir de un cierto ancho el div con clase e1g2 pase a estar dentro de grupo1? Que yo sepa no existe forma de cambiar el padre de un elemento mediante CSS.

Para eso viene a nuestro rescate enquire.js. Nos permite definir funciones JS que se ejecutarán cuando se activen / desactiven las media queries que le pasemos. Para nuestro ejemplo el código sería:

enquire.register("screen and (max-width:950px)", {
match: () => {
let nuevoPadre = document.querySelector("grupo1");
let elementoAmover = document.querySelector("e1g2");
nuevoPadre.appendChild(elementoAmover);
},
unmatch: () => {
let nuevoPadre = document.querySelector("grupo2");
let elementoAmover = document.querySelector("e1g2");
nuevoPadre.appendChild(elementoAmover);
}
});

Usando la misma sintaxis de las media queries tenemos una forma sencilla de mover un elemento de su sitio original a otro sitio dentro del DOM. Por supuesto, mediante CSS podremos definir la posición exacta de ese elemento dentro de “su nueva casa”.

Y además conseguimos esta funcionalidad sin engordar demasiado, la librería solo ocupa 0.8kb una vez minimizada y comprimida.

SAML: información de estado perdida al volver de la autenticación

En uno de mis proyectos uso un servidor externo SAML para autenticar a los usuarios, y ayer me escribieron diciendo que aunque metían los datos correctos en su página de autenticación al llegar a la web les aparecía un mensaje de “Información de estado perdida”.

Cuando esto sucede lo más habitual es que sea porque no se ha podido leer la cookie de la sesión. Ya me había pasado una vez debido a que los usuarios entraban en mi web por un dominio con www y el servidor SAML los redirigía a una página del dominio sin www y al no coincidir la ruta no podía leer la cookie.

Pero ayer el problema se debía a otra cosa, y es que estuve actualizando la versión de PHP y revisando el php.ini añadí la opción de que la cookie de sesión fuera segura, que no estaba activada. ¡Bam! En ese momento empezó a fallar, porque los parámetros de configuración de las cookies de sesión deben ser los mismos en el fichero php.ini y en el fichero config.php de SimpleSaml.

Una vez modifiqué en el fichero config.php de SimpleSaml el parámetro de cookie segura todo volvió a funcionar sin problema. Este error puede suceder también si por ejemplo se activa el nuevo parámetro de SameSite para las cookies de sesión en php.ini y no nos acordamos de hacerlo también en el fichero config.php de SimpleSaml.

Música para programar: el canal de BlueDivine

Siempre estoy buscando música para tener de fondo mientras trabajo, y creo que puede ser interesante ir dejando aquí lo que vaya encontrando para tenerlo de referencia en el futuro.

Mi último descubrimiento ha sido el canal de BlueDivine. Son mezclas de una hora de ChillStep, que es un género que ni sabía que existía pero que resulta que es perfecto para programar.

Directiva de Vue para limitar el número de elementos visibles

Estuve hace poco buscando una directiva de Vue para poder mostrar solo los primeros N hijos de un elemento, y como no encontré ninguna la he creado yo: v-max-items.

Hace poco aprendí a crear paquetes npm, así que está disponible allí, al igual que la clase de JS que hice para que bote un icono: bouncing-icon.

AWS CLI requiere la ruta completa al ejecutable en cron

Al montar un entorno de producción lo primero que hago es preparar el sistema de copias de seguridad: creo una entrada en el cron que ejecuta un programa que vuelca la base de datos con una frecuencia mínima de una vez al día y que depende de la intensidad de uso del servidor.

Pero claro, esta copia de seguridad está en el mismo servidor, por lo que aunque resulta muy útil cuando se produce un error de tipo PICNIC no nos sirve de mucho si el problema es de hardware o perdemos el control del servidor. Necesitamos mantener una copia de esos ficheros en otra parte.

Para esto normalmente yo usaba rsync y copiaba los ficheros en algún otro servidor, pero decidí cambiar a S3 porque me fío más de sus servidores. Los pasos son estos:

  • Crear un usuario en AWS que tendrá acceso solo a un bucket y crear en ese bucket una carpeta backup donde se guardarán las copias de seguridad.
  • Instalar las utilidades de S3 AWS CLI y configurarlas con los datos de acceso de ese usuario de AWS.
  • Meter en el cron una entrada que sincronice nuestra carpeta de copias de seguridad con S3.

El comando para hacer la sincronización es:

aws s3 sync /home/backupDB/ s3://NOMBRE_BUCKET/backup --delete

El –delete indica que si un fichero no está en la carpeta local debemos borrarla de S3. Esto, unido a otra entrada en el cron como esta:

find /home/backupDB/ -mtime +60 -exec rm {} \;

nos permite limitar las copias de seguridad a los últimos dos meses. Dependiendo de los requisitos de este proyecto variamos este valor.

Bueno, pues si uno ejecuta el comando de sincronización verá que funciona estupendamente, lo meterá en el cron y seguirá con su vida tan tranquilo confiando en que todo funcionará bien…

…aunque por si acaso se pondrá una nota para dos días después para revisar que los ficheros se están copiando en S3. Eso hice yo, ¡y menos mal!

Porque dos días después cuando entré en S3 a mirar el bucket vi que solo tenía los ficheros de cuando hice la sincronización a mano desde la línea de comandos. En la carpeta local estaban los ficheros, pero no se habían copiado a S3.

Ejecuté de nuevo desde línea de comandos el trabajo tal y como estaba en el cron y funcionó perfectamente. Revisé que el trabajo estaba bien definido y esperé al día siguiente: los ficheros seguían sin copiarse en S3. Ejecuté otra vez el comando: los ficheros se subieron a S3. En este momento yo ya estaba pegándole bocaos a la mesa.

Rebuscando por Internet encontré un mensaje en Stack Overflow (¿dónde si no?) que daba la solución: hay que poner la ruta completa al ejecutable de aws. La entrada en el cron quedaría entonces así:

0 */2 * * * /usr/local/bin/aws s3 sync /home/backupDB/ s3://NOMBRE_BUCKET/backup --delete

En este caso yo lo tengo configurado para que haga la sincronización cada dos horas. Con este cambio al día siguiente por fin respiré tranquilo al ver que ya aparecían los nuevos ficheros.

Añadir !important a una propiedad CSS desde JavaScript

Estoy haciendo una directiva para Vue que permite limitar el número de elementos que se muestran dentro de otro, y he estado un rato volviéndome loco con un asunto.

Resulta que los elementos que tengo que mostrar / ocultar tienen asignada una propiedad display por CSS, y para ocultarlos debía añadir el !important después de la propiedad:

el.childNodes[x].style.display = "none !important";

Bueno, pues esto no estaba funcionando, y ha sido desesperante porque si probaba a cambiar otras propiedades CSS que no estuvieran ya definidas sí funcionaba, por lo que claramente el problema estaba en que no se estaba aplicando el !important.

Por fin encontré la solución, y es que hay que usar la función setProperty y pasar el !important como tercer parámetro:

el.childNodes[x].style.setProperty("display", "none", "important");

Fuentes en ficheros SVG usados en etiquetas IMG

Cuando en un fichero SVG queremos utilizar una fuente podemos incluirla así:

<defs>
<style>
@import url("https://fonts.googleapis.com/css?family=Montserrat:500,600");
</style>
</defs>

El problema es que si este fichero SVG lo usamos en una página como fuente de una etiqueta IMG el navegador por seguridad no cargará el fichero externo y la fuente no se verá.

La solución es usar Nano para incrustar la fuente en el fichero SVG y que así el navegador pueda usarla sin tener que descargarla.