Medir contraseña con JavaScript y CheckPasswordStrength

Aprende cómo medir la fuerza de la contraseña con JavaScript y la librería CheckPasswordStrength, y evítale futuros disgustos a tus usuarios.

https://github.com/deanilvincent/check-password-strength “A simple npm package that checks the password strength of a certain passphrase. A password strength checker based from Javascript RegEx.”

En la parte final del escrito, he preparado un ejercicio práctico donde implemento la librería. Haz click en la siguiente imagen para ver el resultado final en una ventana nueva:

Ejercicio con CheckPasswordStrength
Ejercicio con CheckPasswordStrength, haz click sobre la imagen para abrir el ejercicio en una ventana nueva

¿Quieres aprender a hacer este ejercicio? Saltar directamente al tutorial

Este artículo es una ampliación del ejercicio que hicimos estudiando la librería JavaScript SuperExpressive. Si no has leído la primera parte, a continuación tienes el enlace:

Crear regular expressions con lenguaje (casi) natural con JavaScript y SuperExpressive

En la anterior entrada vimos brevemente qué son las expresiones regulares y cómo nos pueden ayudar a la hora de validar datos de un formulario.

Tras finalizar el anterior ejercicio, pensé que sería interesante incorporar un indicador de fuerza para la contraseña. Este medidor, mostraría al usuario como de robusta es su contraseña mediante códigos de color.

Así pues, me decidí a crear esta segunda parte. En las siguientes líneas verás cómo implementar esta funcionalidad paso a paso. 

Un mar de opciones a nuestra disposición

Como suele decirse,reinventar la rueda es una mala idea, de modo que empecé por buscar si ya existe alguna solución entre los paquetes de npmjs.com.

Efectivamente, tras unos pocos segundos de búsqueda, tenía cientos de resultados en mi pantalla.

Resultados en npmjs tras buscar "password stength"
Resultados en npmjs tras buscar «password stength»

Este tipo de situaciones son habituales, por consiguiente, es recomendable comparar los indicadores de calidad, popularidad y mantenimiento de los distintos «packages».

Finalmente opté por utilizar “check-password-strength”. Una microlibrería JS, para conocer la fiabilidad de una contraseña mediante una sencillísima API. Medir una contraseña con JavaScript y CheckPasswordStrength, parecía una opción viable.

CheckPasswordStrength también utiliza regex internamente para su propósito. De modo que, es perfecta para ejemplificar un poco más la utilidad de las expresiones regulares.

Medir contraseña con JavaScript y CheckPasswordStrength

Esta librería fué creada por Mark Deanil Vicente. A pesar de que no tiene un índice de popularidad muy elevado, es descargada más de 18K veces a la semana. El comando para instalarla es “npm i check-password-strength”.

Para usarla, solo hay que llamar a la función  “passwordStrength()”, pasándole la cadena de texto que actúa como password.

La librería devolverá toda la información necesaria a través de un objeto con cuatro propiedades. La primera de estas propiedades, es “id”. Ésta indica la fuerza de la contraseña con un valor numérico que va del 0 al 3.

Por contra, si en vez de un número, se quiere obtener ese mismo dato en forma de texto, la propiedad “value” muestra la fuerza con una palabra descriptiva.

Otra propiedad especialmente útil es “contains”. Se trata de una array de “strings” que indican los distintos tipos de carácteres que contiene la password. Gracias a esta característica, se puede advertir al usuario de que le falta incluir, por ejemplo, una letra mayúscula, un número o un carácter especial.

Por último, el objeto también tiene un atributo “length”, indicando la longitud de la contraseña. En realidad este parámetro no da ninguna información relevante, ya que se trata de una información que ya conocíamos de antemano. Aún así, es útil tener este dato accesible.

Para realizar la valoración de fuerza, CheckPasswordStrength utiliza unas opciones de configuración definidas por defecto. Estas opciones exportar con el nombre “defaultOptions”, y se pueden reescribir pasando otro objeto como segundo parámetro.

En cualquier caso, los parámetros por defecto, ya funcionan muy bien.

Crea un medidor visual de passwords

A continuación implementaremos la librería aprovechando el código desarrollado en la primera parte.

Empezaremos editando un poco el código HTML. Primero modificando la imagen de cabecera para dar un nuevo “look” al ejercicio.

<img src="imgs/locker_svg.svg" alt="" class="img-locker" />

Por cierto, ésta imagen la hemos creado nosotros con Figma especificamente para este artículo. Aunque no sea una librería JS algún día haremos un vistazo a ese genial programa.

Locker
Lockpad, defensor de passwords

Seguidamente, añadimos un contenedor con su etiqueta “label” justo a continuación del anterior campo “password”.

<label for="email">Fuerza de la contraseña</label>
<div class="password-strength_container"></div>

Adicionalmente, también incluimos la propiedad “data-contains” a cada elemento del listado de restricciones que creamos.

<ul>
        <li data-contains="8-chars">
          Al menos 8 carácteres.
        </li>
        <li data-contains="upper-lower-and-num">
          Debe contener al menos una letra en mayúscula, una en minúscula, y un
          número.
        </li>
        <li data-contains="special-chars">
          Puede contener carácteres especiales.
        </li>
</ul>

Estas propiedades nos van a permitir tachar a tiempo real las restricciones que se vayan cumpliendo.

Ampliaremos los estilos CSS, pero para ello crearemos un archivo independiente y lo importaremos a nuestro index.scss.

@import "./password-strength.scss";

En esta nueva hoja de estilos, incluiremos las siguientes clases. 

.img-locker {
  display: block;
  margin: 0 auto 40px auto;
  width: 100%;
}
.password-strength_container {
  height: 3px;
  background-color: rgb(220, 220, 220);
  margin-bottom: 20px;
  &:after {
    transition: all 0.3s ease-in-out;
    height: 100%;
    width: 100%;
    display: block;
    content: "";
    transform-origin: 0% 0%;
    transform: scaleX(0);
    background-color: rgb(36, 0, 0);
  }
  &.level-1 {
    &:after {
      transform: scaleX(0.33333);
      background-color: rgb(255, 28, 28);
    }
  }
  &.level-2 {
    &:after {
      transform: scaleX(0.66666);
      background-color: rgb(180, 196, 0);
    }
  }
  &.level-3 {
    &:after {
      transform: scaleX(1);
      background-color: rgb(1, 255, 18);
    }
  }
}
[data-contains] {
  &.crossed-out {
    text-decoration: line-through;
  }
}

Como se puede ver, el indicador de fuerza, cambiará de tamaño y color en función de la clase que se añade dinámicamente.

Finalmente, crearemos el script con la funcionalidad también en un archivo aparte. Deberemos incluir este archivo en programa principal index.js.

import "./scripts/password-strengh-checker";

El código de “password-strength-checker.js” es sencillo, pero lo desgranamos por partes, para una mejor comprensión. Por supuesto, la primera instrucción es importar la librería.

import { passwordStrength } from "check-password-strength";

El siguiente paso será guardar referencias a algunos elementos del DOM. Por una parte, guardamos el contenedor que hemos creado, y por la otra, el conjunto de elementos de la lista.

const stengthContainer = document.querySelector(".password-strength_container");
const containsList = document.querySelectorAll("[data-contains]")

Como vemos, “data-contains” también nos sirve de selector.

Tras guardar las referencias, seleccionamos el input de texto para la contraseña, y escuchamos los eventos de tipo “keyup”.

document
  .querySelector('input[name="password"]')
  .addEventListener("keyup", (e) => {
    stengthContainer.classList.remove("level-1", "level-2", "level-3");
    const strength = passwordStrength(e.target.value);
    console.log(strength);
    containsList.forEach((listElement) => {
      listElement.classList.remove("crossed-out");
      switch (listElement.dataset.contains) {
        case "8-chars":
          if (strength.length >= 8) {
            listElement.classList.add("crossed-out");
          }
          break;
        case "special-chars":
          if (strength.contains.includes("symbol")) {
            listElement.classList.add("crossed-out");
          }
          break;
        case "upper-lower-and-num":
          if (
            strength.contains.includes("lowercase") &&
            strength.contains.includes("uppercase") &&
            strength.contains.includes("number")
          ) {
            listElement.classList.add("crossed-out");
          }
          break;
      }
    });
    if (strength.id === 0) {
      return;
    }
    stengthContainer.classList.add(`level-${strength.id}`);
  });

En la función de “callback” del evento ejecutaremos un conjunto de instrucciones. Vamos a ver punto por punto a continuación.

Eliminar todas las clases del contenedor, y obtener la información de fuerza del input, gracias a la librería «check-password-strength».

stengthContainer.classList.remove("level-1", "level-2", "level-3");
const strength = passwordStrength(e.target.value);

Recorremos todos los elementos de la lista, y en función del valor de “data-contains”, comparamos cada regla. En caso de que se cumpla, añadimos la clase “crossed-out”.

    containsList.forEach((listElement) => {
      listElement.classList.remove("crossed-out");
      switch (listElement.dataset.contains) {
        case "8-chars":
          if (strength.length >= 8) {
            listElement.classList.add("crossed-out");
          }
          break;
        case "special-chars":
          if (strength.contains.includes("symbol")) {
            listElement.classList.add("crossed-out");
          }
          break;
        case "upper-lower-and-num":
          if (
            strength.contains.includes("lowercase") &&
            strength.contains.includes("uppercase") &&
            strength.contains.includes("number")
          ) {
            listElement.classList.add("crossed-out");
          }
          break;
      }
    });

Finalmente, dependiendo de la propiedad “id” de la fuerza, actualizamos la clase del contenedor.

if (strength.id === 0) {
  return;
}
stengthContainer.classList.add(`level-${strength.id}`);

Crea un medidor visual de passwords

Con esto terminamos este breve repaso a los regex, espero que te haya sido de utilidad. Medir la fuerza de la contraseña con JavaScript y CheckPasswordStrength, y mostrar esa información puede contribuir a evitar futuros disgustos a nuestros usuarios.

Te dejo el enlace al repositorio en Github de CheckPasswordStrength. Repositorio de CheckPasswordStrength

También encontrarás el ejercicio completo en el repositorio público de libreriasjs. Repositorio de libreriasjs

¿Quieres seguir aprendiendo cómo mejorar la seguridad de tus interfaces? Aprende a validar datos tanto en el frontend, como en el backend en este artículo sobre Yup

Yup, la librería JavaScript para validar datos de formularios

Nos vemos pronto, un abrazo desarrolladores!

Deja un comentario