> ## Content Index
> Fetch the complete content index at: https://blog.gonzaleztroyano.es/llms.txt
> Use this file to discover other available public pages before exploring further.

# Generación de contraseñas con Cloudflare Workers
- URL: https://blog.gonzaleztroyano.es/cloudflare-workers-password-generator/
- Published: 2022-04-08T05:50:00.000Z
- Updated: 2023-05-17T15:35:51.000Z
- Description: En este artículo se trata el proceso y las opciones para la generación de contraseñas utilizando Cloudflare Workers.
- Author: Pablo González Troyano
- Tags: Cloudflare

Este es realmente un desarrollo de esos en los que inviertes más tiempo del que acabas ahorrando para solucionar un problema que ya tenía solución, pero con el que aprendes *mogollón*. Sin duda, los mejores. 

Si eres un poquito friki ?, estoy seguro de que en algún momento has tenido la necesidad de generar contraseñas. Ya sea para darte de alta en algún servicio online, si eres administador/a de algún entorno para cambiársela a algún usuario/a o para cualquier otra función. Contraseñas, contraseñas, contraseñas, ¡necesitamos contraseñas!

En una de esas veces en la que era necesario, en vez de acceder a uno de los millones de generadores online existentes me pregunté si podría crear alguno. Ya tenía el *runrún* de *cacharrear* algo con los [Workers](https://workers.cloudflare.com/?ref=blog.gonzaleztroyano.es) de [Cloudflare](https://www.cloudflare.com/?ref=blog.gonzaleztroyano.es). Se juntó el hambre con las ganas de comer y hasta aquí hemos llegado. 

¿Pero qué es esto de los Workers de Cloudflare? Muy buena pregunta. La propia empresa lo define de la siguiente manera en una entrada de blog:

> Workers es una plataforma que le permite ejecutar JavaScript en el perímetro global de Cloudflare de más de 175 centros de datos. Con solo unas pocas líneas de código, puede enrutar solicitudes HTTP, modificar respuestas o incluso crear nuevas respuestas sin un servidor de origen.

Si simplemente quieres una contraseña y estás trabajando bajo Linux, recuerda que puedes utilizar el siguiente comando:

```bash
openssl rand -base64 24 # Siendo 24 variable
# Resultado: EcidUiQ2crhxJrC0y99Y4JfexuuF7Kna
```

## Instrucciones de uso y posibilidades

Puedes acceder a la versión *live* de este worker a través del siguiente enlace:

[genera-password.gonzaleztroyano.es](https://genera-password.gonzaleztroyano.es/?ref=blog.gonzaleztroyano.es)

Según se accede a esta dirección devolverá la cadena de texto generada. Nada más. Esto es especialmente importante para usarlo en *scripts* en las que no son necesarias, y de hecho incomodan, las etiquetas HTML. 

Te devolverá una cadena de **24** caracteres aleatorios formada por números, letras en mayúscula y minúscula y caracteres especiales. 

Pero, ¿y si solo quiero 12 caracteres? ¿Y si no quiero caracteres especiales? ¿Y si únicamente necesito números en la cadena aleatoria? ¡Está todo pensado! 

Vamos a ver las distintas opciones: 

| **Ruta**                                                                           | **Longitud** | **Caracteres** | **Ejemplo**                 |
| ---------------------------------------------------------------------------------- | ------------ | -------------- | --------------------------- |
| [/](https://genera-password.gonzaleztroyano.es/?ref=blog.gonzaleztroyano.es)       | 24           | Todos          | ck%dfDCXNu\]ng+\~usM\|&&y{O |
| [/8](https://genera-password.gonzaleztroyano.es/8?ref=blog.gonzaleztroyano.es)     | 8            | Todos          | @JaeFdgR                    |
| [/n](https://genera-password.gonzaleztroyano.es/n?ref=blog.gonzaleztroyano.es)     | 24           | Solo números   | 458399725095831641438718    |
| [/a](https://genera-password.gonzaleztroyano.es/a?ref=blog.gonzaleztroyano.es)     | 24           | Alfabéticos    | KaSIttubXUCFrCCFmepblJNm    |
| [/A](https://genera-password.gonzaleztroyano.es/A?ref=blog.gonzaleztroyano.es)     | 24           | Alfanuméricos  | HBavK5MZHkXSCWGaftIMeaSf    |
| [/8/a](https://genera-password.gonzaleztroyano.es/8/a?ref=blog.gonzaleztroyano.es) | 8            | Alfabéticos    | FRvHGcmZ                    |
| [/8/n](https://genera-password.gonzaleztroyano.es/8/n?ref=blog.gonzaleztroyano.es) | 8            | Solo números   | 59215032                    |
| [/8/A](https://genera-password.gonzaleztroyano.es/8/A?ref=blog.gonzaleztroyano.es) | 8            | Alfanuméricos  | 3IQW1G9u                    |

?

No hay razón para utilizar ambos modificadores. Si no indicas valor, tomará los predeterminados: 24 de longitud y todos los caracteres. Pero, **importante**: si utilizas ambas, primero has de definir la longitud.

## Código fuente

El worker está escrito en JavaScript y se divide en 3 partes:

- El *eventListener* para cuando se realice la petición.
- La función que "hace la magia".
- La función que maneja la petición y crea la respuesta.

La parte realmente más interesante es la segunda, sin ninguna duda. Así que vamos a *despachar* las otras dos y así nos centramos en "donde hay chicha". 

### EventListener

Simplemente responde al evento con la respuesta de manejador de peticiones (siguiente apartado).

```javascript
addEventListener("fetch", event => {
    event.respondWith(handleRequest(event.request))
})
```

### handleRequest

Es la función a la que llama el *EventListener*, guarda la URL de la petición HTTP como una variable y luego se la pasa a la función *genPassword* para que la trate. Lo que retorne esta función es la respuesta a la petición web. Se añade la cabecera *content-type* para que el navegador lo trate como debe.

```javascript
async function handleRequest(request) {
    const url = new URL(request.url);
    return new Response(genPassword(url.pathname), {
        headers: { 'content-type': 'text/plain' },
    })
}
```

### Función genPassword

Esta es la función principal de la función. Como es un poco extensa, la dividiremos en varios bloques. 

```javascript
function genPassword(pathname) {
    let regex_num = new RegExp('^\/[0-9]+$');
    let regex_alpha = new RegExp('^\/[a,n,A]+$');
    let regex_alphanum = new RegExp('^\/[0-9]+\/[a,n,A]+$');
    var chars = "0123456789abcdefghijklmnopqrstuvwxyz!#$%&()*+,-./:;<=>?@[\]^_{|}~ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
// [COSAS MÁGICAS]
    
 var password = "";
    for (var i = 0; i < passwordLength; i++) {
        var randomNumber = Math.floor(Math.random() * chars.length);
        password += chars.substring(randomNumber, randomNumber + 1);
    }
    console.log('Más información: https://pglez.es/genera-password-overview');
    return password;
}
```

En esta parte de la función, que realmente son dos partes (la inicial y la final) se declaran las variables iniciales y se calcula la contraseña. Las expresiones regulares que se ven al comienzo son las que se usan para comparar el path de la petición HTTP (pasada a la función como *pathname*) con las distintas posibilidades vistas en la tabla anterior en este artículo.

La parte faltante del código se organiza de la siguiente manera:

```
Si [[ pathname == '/' ]] 
  |
  |--> Longitud = 24 y listo

Si [[ pathname concuerda con la expresión regular 'regex_num' ]]
  |
  |--> Haz cosas (1)
   
Si [[ pathname concuerda con la expresión regular 'regex_alpha' ]]
  |
  |--> Haz cosas (2)

Si [[ pathname concuerda con la expresión regular 'regex_alphanum' ]]
  |
  |--> Haz cosas (3)

else --> Devuelve un error

```

Vamos a verlas a continuación.

### Haz cosas 1: *regex\_num*

Esta opción solo actúa cuando únicamente se añaden números al path. */30* o /8*,* por ejemplo. Es realmente sencillo, como vamos a ver a continuación. Únicamente retira la barra o slash de *pathname* y lo convierte a entero, para luego asignarle este valor a la variable que limita la función de cálculo aleatorio.

```javascript
else if (regex_num.test(pathname)) {
        pathname = parseInt(pathname.substr(1));
        var passwordLength = pathname;
    }
```

### Haz cosas 2: *regex\_alpha*

Si bien esta parte del código es algo más extensa respecto a la anterior, es medianamente simple. 

```javascript
else if (regex_alpha.test(pathname)) {
        var passwordLength = 24;
        pathname = pathname.substr(1);
        if (pathname == 'a') {
            var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        } else if (pathname == 'n') {
            var chars = "1234567890";
        } else if (pathname == 'A'){
            var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
        } else {
            return "ERROR en la solicitud. +info: https://pglez.es/genera-password-overview - 1";
        }
```

Como únicamente se ha indicado en el path la letra, se entiende que el valor por defecto de 24 de longitud es correcto. Por tanto, definimos a 24 *passwordLength*. Aunque no es necesario, por estandarizar un poco, se retira de nuevo el slash de *pathname.* El resto es sencillo, según qué letra llegue a la función los posibles caracteres que pueden usarse en el aleatorio varían. Si bien el último *else* no debería ejecutarse nunca, se añade por si evoluciona el código. 

### Haz cosas 3: *regex\_alphanum*

Este bloque de código se ejecutará cuando el pathname coincida con la expresión regular *'^\\/\[0-9\]+\\/\[a,n,A\]+$'*. Es realmente una combinación de los dos fragmentos anteriores:

```javascript
else if (regex_alphanum.test(pathname)) {
        let gen_opt = pathname.substr(-1);
        var passwordLength = parseInt(pathname.substr(1).slice(0, -2));
        if (gen_opt == 'a') {
            var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        } else if (gen_opt == 'n') {
            var chars = "1234567890";
        } else if (gen_opt == 'A'){
            var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
        } else {
            return "ERROR en la solicitud. +info https://pglez.es/genera-password-overview - 2";
        }
```

En las primeras 2 líneas del condicional vemos:

- Acceder a la **opción** indicada en el path:  
```javascript  
let gen_opt = pathname.substr(-1);  
```  
Guardamos el último caracter por la derecha. Gracias a la expresión regular sabemos que no va a llegar hasta aquí una entrada que no cumpla con lo indicado.
- Acceder a la **longitud** indicada en el path:  
```javascript  
var passwordLength = parseInt(pathname.substr(1).slice(0, -2));  
```  
Para la longitud deseada debemos mantener únicamente la parte central del pathname: ni la barra inicial, ni la opción contenida en los dos últimos caracteres.  
Esto es justo lo que hacemos aquí. En vez de "coger" la parte que nos interesa, que puede cambiar dependiendo de la longitud deseada (4,10,200,1000...), retiramos lo que sabemos que siembpre se va a mantener: un caracter por la izquierda y dos por la derecha.

La parte que resta es igual a lo visto anteriormente, según la opción indicada, se utilizaran unos caracteres u otros para generar la contraseña aleatoria. En cualquier otro caso retornará un error. 

Para terminar, tenemos el último *else*, que se activará en caso de no concordar con ninguna expresión regular de las anteriores:

```javascript
    else {
        return "ERROR en la solicitud. +info: https://pglez.es/genera-password-overview - 3";
    }
```

Para terminar la función, justo después del cálculo de la contraseña tenemos un *console.log* para volcar un enlace con más información y el *return* del resultado:

```javascript
	console.log('Más información: https://pglez.es/genera-password-overview');
    return password;
```

## Resumen y tareas pendientes

De forma sencilla y compatible con automatizaciones podemos generar contraseñas con una simple petición web. Estas contraseñas son medianamente configurables, lo que permite aplicarlas en prácticamente cualquier ámbito. 

La ventaja de usar esta herramienta y no otras recae en la rapidez y en la no existencia de rastreadores, publicidad y gasto de ancho de banda. El objetivo es generar una contraseña, nada más. 

Queda pendiente revisar por si hubiera lugar para optimización del código, asi como evitar la solicitud de la generación de contraseñas de longitudes altas (del orden de decenas miles). En cualquier caso, Cloudflare parará la ejecución cuando supere ciertos milisegundos de CPU, al estar en el plan gratuito.

El código completo de este worker está disponible en Github:

[Ver código en Github](https://github.com/gonzaleztroyano/gonzaleztroyano/blob/main/cloudflare%5Fworker%5Fpassword%5Fgenerator.js?ref=blog.gonzaleztroyano.es)

---

## ¿Alguna duda?

No dudes en [ponerte en contacto conmigo](https://blog.gonzaleztroyano.es/sobre-mi/#%C2%BFalguna-duda) para cualquier duda, sugerencia, queja o aclaración que creas necesaria. ¡Será un placer hablar contigo!