Video Summary and Transcription
Esta charla proporciona una introducción a la criptografía con Node.js, cubriendo conceptos de cifrado, algoritmo AES-256-CBC, vector de inicialización para el cifrado, función de derivación de claves y sal, aleatoriedad y acuerdo de claves, distribución de claves y RSA, firma y verificación, certificados de clave pública y confianza en la jerarquía de certificados.
1. Introducción a la Criptografía con Node.js
En esta charla, hablaré sobre el dominio de los fundamentos de la criptografía con el módulo crypto de Node. La criptografía es la ciencia de la comunicación secreta, lo cual es crucial en nuestro mundo en línea. Node.js tiene un módulo crypto incorporado que ofrece algoritmos criptográficos comunes para su uso en aplicaciones. La documentación del módulo asume familiaridad con los conceptos básicos de la criptografía, así que proporcionaré un atajo cubriendo los conceptos y el uso práctico. ¡Comencemos!
Así que en esta charla, me gustaría hablarles sobre esto. Oh, lo siento. El título de la charla está encriptado. Así que apliquemos la desencriptación.
Hoy quiero hablarles sobre esto. De acuerdo. Dominando los fundamentos de la criptografía con el módulo crypto de Node. Así que este título es un poco largo. Así que vamos a desglosarlo. Primero hablemos sobre qué es la criptografía. La criptografía es la ciencia o el estudio de los medios de comunicación secreta. Y como pueden imaginar, en nuestro mundo en línea, esto juega un papel muy importante.
Afortunadamente, dentro de Node.js tenemos un módulo incorporado llamado el módulo crypto y está ahí para ofrecer algoritmos criptográficos comunes que puedes usar en tu aplicación. Ahora este es un módulo incorporado al igual que FS, por lo que puedes comenzar a usarlo de inmediato sin instalar nada. Además, como es un módulo incorporado, tiene documentación. Así que cuando quería comenzar a usarlo por primera vez, aquí es donde fui. Y descubrí que este tipo de documentación no es realmente adecuada para un principiante como yo. Porque es una estructura muy plana. Hay muy poca información sobre cada método. Asume que ya estás bastante familiarizado con los conceptos básicos de la criptografía, qué hace cada algoritmo. Y solo te da la sintaxis específica en Node.js. Así que tuve que volver al principio y leer sobre los conceptos. Y aprender sobre qué hace cada algoritmo diferente, qué problemas resuelve, cuándo es aplicable usarlo. Y solo entonces, cuando tenía estos datos conceptuales, pude volver y ver la sintaxis real en Node.js para poder ser práctico y experimentar con escribir código que use ese algoritmo. Y este es el proceso a través del cual quiero darte un atajo en la charla de hoy. Quiero que cubramos los conceptos básicos de la criptografía, la información conceptual, y luego ser prácticos y ver cómo podemos usar estas cosas en Node.js.
Así que empecemos. Mi nombre es Yonatan Navarro. Soy un desarrollador web de Wix.com.
2. Conceptos de Encriptación y AES-256-CBC
El primer concepto en criptografía es la encriptación, que permite una comunicación segura a través de un canal inseguro. Para realizar la encriptación, necesitamos elegir un algoritmo de encriptación. Un algoritmo popular es AES-256-CBC, que garantiza seguridad y privacidad. El tamaño de clave del algoritmo de 256 bits proporciona una gran cantidad de combinaciones de claves para que los atacantes adivinen. El modo CBC y el vector de inicialización mejoran la seguridad de la encriptación. El proceso de encriptación involucra el texto plano y una clave compartida entre el remitente y el receptor.
Así que el primer concepto en criptografía del que hablaremos es esta idea de encriptación. Esto permite que dos partes, digamos Alice y Bob, intercambien información a través de un canal inseguro como Internet sin tener que preocuparse de que alguien que haya capturado los mensajes que se envían pueda entender el significado detrás de estos mensajes. Y por eso hacemos encriptación.
Entonces, lo primero que debemos considerar para realizar la encriptación es qué tipo de algoritmo de encriptación usar. Hay bastantes de ellos disponibles. Todos funcionan básicamente mediante el concepto de sustitución y transformación del mensaje original y luego hacer lo contrario para desencriptar. Ahora, esta parte del code que estoy mostrando aquí es en realidad la primera parte del code del módulo crypto que estoy mostrando hoy, y esto se llama la función getCiphers. Y como su nombre sugiere, esto devolverá una lista de todos los algoritmos criptográficos que puedes ejecutar en tu máquina usando el módulo crypto. Por ejemplo, cuando lo ejecuto en mi máquina, devuelve 171 resultados. Así que elijamos uno para ilustrar esta idea de encriptación.
Entonces, hay una familia de algoritmos de encriptación conocidos como AES, Advanced Encryption Standard. Y como su nombre sugiere, estos son algoritmos lo suficientemente advanced como para ser utilizados en aplicaciones modernas. Y es un estándar, por lo que se implementan en diferentes entornos. Específicamente, echemos un vistazo a AES-256-CBC. Así que desglosemos esto. Entonces, 256 se aplica aquí al tamaño de la clave. Hablaremos sobre la clave y el papel que desempeña en la desencriptación en un momento. Pero esta es esencialmente la parte del algoritmo que garantiza la seguridad y privacidad de la comunicación. Lo que un atacante como Yves podría intentar hacer es probar todas las combinaciones posibles de la Entonces, si usamos una clave de 256 bits, significa que el atacante tendría que probar una cantidad astronómica de clave que se utiliza. combinaciones de claves diferentes.
Ahora, CBC significa cipher block chaining. Este es un modo de encriptación donde, como parte del proceso de encriptación, el mensaje se divide en diferentes bloques. Y para calcular el primer bloque, debes proporcionar algo que se llama un IV o vector de inicialización. Hablaremos sobre su papel y cómo hace que nuestra encriptación sea más segura en un momento. Así que hablemos sobre el proceso de encriptación. Digamos que Yves quiere enviarle a Bob un mensaje encriptado. Necesitaría el texto plano, que es el mensaje original, la clave, de la que hablaremos más adelante. Hablaremos sobre cómo decidimos qué valor usar como clave y cómo transportar la clave. Pero por ahora, digamos que es un fragmento de data que Yves tiene y Bob debe tener una clave idéntica, es decir, el mismo fragmento de data, para poder realizar la desencriptación.
3. Encriptación con Vector de Inicialización (IV)
Para garantizar diferentes resultados de texto cifrado, se utiliza un Vector de Inicialización (IV) aleatorio en la encriptación. En Node.js, Alice utiliza la función createCipherIV para encriptar su texto plano utilizando el algoritmo, la clave y el IV elegidos. Bob utiliza la función createDecipherIV para desencriptar el texto cifrado utilizando la misma clave y IV. Este proceso permite una comunicación segura entre Alice y Bob.
Ahora también tenemos el IV que mencioné anteriormente. Para eso, simplemente usaremos un valor completamente aleatorio cada vez que queramos aplicar la encriptación. Digamos que todas las mañanas, Alice le envía a Bob un mensaje de saludo. Siempre está utilizando el mismo texto plano y la misma clave. Debido a que está utilizando un IV diferente cada vez, el algoritmo de encriptación que están utilizando, que es una función determinista, devuelve una salida diferente cada vez debido al IV diferente. Por lo tanto, el texto cifrado resultante, que es el mensaje que se envía a través de Internet, será diferente cada vez. Esto dificultará que Yves intente identificar relaciones entre el texto plano y el texto cifrado. Luego, Yves envía esta información, el IV, el texto cifrado y el algoritmo a Bob, y Bob, utilizando el mismo valor como clave, puede realizar la desencriptación. Veamos cómo se hace esto en Node.js. Tenemos la encriptación de Alice. Ella elige el algoritmo a utilizar. Toma el texto plano. Observa que el texto plano no se guarda como una cadena, sino que se convierte en un búfer. Genera un valor IV aleatorio utilizando la función random bytes y carga la clave en la memoria. Más adelante hablaremos sobre qué valor usamos como clave. Luego está lista para realizar la encriptación llamando a createCipherIV, pasando el algoritmo, la clave y el IV. Luego llama a update y final en el objeto cipher, lo que le da el texto cifrado, que puede compartir con Bob.
4. Función de Derivación de Clave y Salt
Bob recibe el IV, el texto cifrado y el algoritmo, carga la clave idéntica en la memoria desde su copia, y luego hay una API que se ve muy similar, crea decipherIV y llama a update y final en el objeto decipher. Así que hablamos sobre la clave. No queremos usar una contraseña memorable para humanos como la clave. En su lugar, podemos usar una función de derivación de clave (KDF). Un KDF es similar a una función hash pero es intencionalmente lento, lo que ralentiza a los atacantes. Para mejorar aún más la seguridad, se utiliza un valor aleatorio llamado salt como segundo parámetro. Esto asegura que incluso si se obtienen contraseñas conocidas, el atacante aún necesita ejecutar la función KDF para cada iteración con el valor de salt. En Node.js, se puede utilizar la función KDF s-script del módulo Crypto, junto con otras dos KDF incorporadas.
Bob recibe el IV, el texto cifrado y el algoritmo, carga la clave idéntica en la memoria desde su copia, y luego hay una API que se ve muy similar, crea decipherIV y llama a update y final en el objeto decipher. Y esto devolverá el texto plano original que Alice quería compartir con Bob.
Así que hablamos sobre la clave. ¿Qué valor podemos usar como clave? Podríamos ser tentados a usar una contraseña memorable para humanos como la clave en sí misma, porque es fácil de recordar. Pero esto es un problema. Mencionamos antes que tenemos un gran espacio de opciones para almacenar la clave, ¿verdad? Con 256 bits. Si Eve, el atacante, puede asumir que Alice está utilizando una contraseña memorable para humanos como la clave, entonces Eve no tiene que probar todas las combinaciones dentro de ese espacio realmente grande de opciones. En su lugar, ella puede limitarse a un conjunto mucho más estrecho de contraseñas memorables para humanos.
Por eso no queremos usar una contraseña memorable para humanos como la clave. Entonces, ¿qué podemos usar si aún queremos confiar en algo que recordamos como base de nuestra seguridad y nuestra clave? Para esto, podemos usar lo que llamamos una función de derivación de clave, o KDF en resumen. Un KDF es similar a una función hash, con la que puedes estar familiarizado al verificar la integridad de los archivos. Es una función determinista unidireccional, y le das la contraseña memorable para humanos y la expande. La salida es algo que proporcionará una clave mucho más fuerte y más larga, que podemos usar para nuestra encriptación. A diferencia de una función hash normal, el KDF está diseñado para ser intencionalmente lento, lo cual no es algo que veas a menudo cuando diseñamos cosas para que sean lentas a propósito.
La razón por la que hacemos esto es porque el hecho de que esta función sea lenta no ralentizará a Alice, porque solo tiene que ejecutar esta función una vez para la contraseña que recuerda, pero ralentizará a Eve. Lo que Eve podría intentar hacer es descargar la lista, digamos, de las 10,000 contraseñas más comúnmente utilizadas de Internet, y luego, para derivar la clave de ellas en cada iteración en esa lista de 10,000 opciones, necesitará ejecutar esta costosa función KDF. Esto va a ralentizar a Eve, el atacante. Esto suena bien. Entendemos el valor del KDF. Pero si lo piensas, aún falta una parte porque lo que Eve puede hacer no es ir a Internet y simplemente descargar una lista de las 10,000 contraseñas más comúnmente utilizadas. Ella puede descargar una lista de valores precalculados cuando esas contraseñas comunes se pasan por algún KDF conocido que ella puede asumir que se utiliza en la encriptación. Y si este es el caso, si esto es posible, entonces el KDF no la está ralentizando en absoluto, y solo está complicando la vida de Alice y Bob.
Por eso, crucialmente, en un escenario del mundo real con un KDF, hay un segundo parámetro, no solo la contraseña, sino otro valor aleatorio, que llamamos valor de salt. Entonces, incluso si Eve tiene acceso a nuestro salt, para intentar estas contraseñas conocidas, ella tendrá que pagar el costo de ejecutar la función para cada iteración con el valor de salt. Y esto es lo que se asegura de que el KDF realmente la ralentice y evite que fuerce bruta nuestra contraseña. Veamos cómo se hace esto en Node.js. Podemos echar un vistazo al KDF s-script, que es un KDF conocido, secure crypt. Está disponible dentro del módulo Crypto. Y puedes ver que tomamos la contraseña, generamos bytes aleatorios como salt, pasamos eso a la función s-script, y obtenemos una clave que podemos usar. Otra mención notable aquí, tenemos otras dos KDF incorporadas en el módulo Crypto.
5. Randomness and Key Agreement
Tenemos HKDF y PBKDF2. Para generar valores aleatorios en Node.js, evita usar math.random() y utiliza las funciones random bytes, random fill, random int y random uuid del módulo Crypto. Para acordar una clave compartida, se utiliza el sistema RSA, donde Bob genera una clave privada y pública, y Alice puede cifrar un mensaje usando la clave pública de Bob.
Tenemos HKDF y PBKDF2. Muy bien, como podemos ver, poder generar valores aleatorios juega un papel importante en la criptografía. Entonces, la primera regla para generar aleatoriedad en Node.js y en JavaScript es no tentarse a usar la función math.random() familiar porque, como se indica en la documentación de MDN, no se considera segura desde el punto de vista criptográfico. Entonces, ¿qué usamos? Afortunadamente, dentro del módulo Crypto, tenemos una función que nos permite generar valores aleatorios. Como vimos, como se puede ver, estas son asíncronas, pero para usarlas como promesas, debes llamar a u-tilde.promisify() en ellas. Ahora, como vimos antes, tenemos la función random bytes. Le das un tamaño y devuelve un búfer de ese tamaño con valores aleatorios en su interior. Tienes random fill, que toma un búfer existente y reemplaza todos los valores en su interior o un subconjunto de ellos con valores aleatorios. Tienes random int, que dado un valor mínimo y máximo, devuelve un número entero dentro de ese rango. Y tienes random uuid. Muy bien, hablamos de la clave antes y dijimos que mantener la clave conocida solo por las partes relevantes es realmente lo que garantiza la seguridad del cifrado. Entonces, ¿qué valor usamos como clave? Cubrimos eso cuando hablamos de las KDF.
6. Distribución de Claves y RSA
Para acordar una clave compartida, podemos usar el método RSA. En este sistema, Bob genera una clave privada y pública, y Alice puede cifrar un mensaje usando la clave pública de Bob. Para realizar el cifrado y descifrado en Node.js, Bob puede generar un par de claves usando la función generateKeyPair y exportar las claves pública y privada. Alice puede cifrar un mensaje leyendo la clave pública de Bob y llamando a public encrypt, mientras que Bob puede descifrar el texto cifrado usando su clave privada.
Esa es una forma de decidir el valor de la clave. Pero ¿cómo acordamos que dos partes tengan la misma clave? Si Alice y Bob solo están hablando en línea, entonces nunca tienen el lujo de reunirse en persona y acordar la clave allí cuando saben que Eve no está escuchando. Entonces este es un gran problema, y esto es algo en lo que Alice pensó mucho. Y francamente, yo también pensé mucho en ello. Y en realidad, este fue un problema importante en la criptografía en el que muchas personas inteligentes pensaron durante muchos años.
Afortunadamente, en la década de 1970, un grupo de científicos publicó una solución elegante a este problema. Y el método que idearon se conoce por sus iniciales, RSA. Veamos su solución. En este tipo de sistema, Bob genera dos claves. Su clave privada y una clave pública. Y hay un vínculo matemático entre ambas. Como sugiere el nombre, la clave pública se hace pública, y la clave privada, Bob la guarda en un lugar seguro al que solo él tiene acceso.
Ahora, si Alice quiere enviarle un mensaje a Bob, puede tomar su clave pública, perdón, la clave pública de Bob, y el texto plano, y usarlos para realizar el cifrado y obtener el texto cifrado. Luego puede enviar el texto cifrado a Bob. Y luego Bob realiza el descifrado usando su clave privada. Al usar una clave diferente para el cifrado y el descifrado, podemos sortear y evitar por completo el problema de la distribución de claves. Entonces veamos cómo se hace esto en Node.js. Primero, Bob quiere generar un par de claves. No tiene que hacer esto solo para la correspondencia con Alice. Puede usar el mismo par de claves para comunicarse con todos. Entonces solo tiene que hacer esto una vez si así lo desea. Usamos la función generateKeyPair. Y decimos que queremos usar esto para la comunicación RSA. Y luego tiene acceso a la clave pública, que puede exportar a un archivo y compartir, y la clave privada, que puede exportar a un archivo y guardar en un lugar seguro donde solo él tenga una copia.
Ahora, si Alice quiere realizar el cifrado, puede leer la clave pública de Bob en la memoria. Puede tomar el mensaje original, convertirlo en un búfer, y llamar a public encrypt en él para obtener el texto cifrado. Pasando la clave pública, el texto plano y un valor constante, eligiendo qué tipo de relleno usar. Ahora, para realizar el descifrado, Bob obtiene el texto cifrado, lee su clave privada en la memoria, y llama a private decrypt del módulo Cryptol, pasando los parámetros similares. Y lo que obtendrá de vuelta es el mensaje original en texto plano. Como puedes ver, esta es una solución bastante elegante al problema de la distribución de claves.
7. Menciones Notables y Firma
Existen otras menciones notables en criptografía, como el intercambio de claves de Diffie-Hellman y la curva elíptica de Diffie-Hellman. En un mundo donde es posible la encriptación, surge el problema de verificar la identidad del remitente. Para abordar esto, se puede utilizar la firma y la verificación. Al generar una firma utilizando una clave privada y verificarla utilizando una clave pública, se puede garantizar la autenticidad de un mensaje. En Node.js, la firma se realiza utilizando crypto.sign y la verificación se realiza utilizando crypto.verify. Además, el módulo crypto incluye la función createHMAC para el código de autenticación de mensajes basado en hash.
También tenemos otras menciones notables aquí. Hubo otro grupo en la década de 1970 que publicó una solución diferente al problema de distribución de claves. Y su solución se llama intercambio de claves de Diffie-Hellman. También está disponible en el módulo Cryptol. Y tienen otro algoritmo que se utiliza ampliamente hoy en día, que se llama curva elíptica de Diffie-Hellman, que también está disponible.
Entonces, si lo piensas, hemos llegado lejos, y con este sistema donde todos tienen una clave privada y una clave pública, podría parecer que no hay más problemas en criptografía. Pero si lo piensas, en este tipo de mundo, cualquiera puede enviarme un mensaje encriptado. Pero, ¿cómo puedo saber que ese mensaje encriptado realmente proviene de una entidad específica que es quien dice ser? Aquí es donde hablamos de firma y verificación.
Digamos que Alice es una organizadora de JS Nation, y ella quiere enviarle a Bob una entrada. Bob quiere acercarse a la puerta del lugar y decir, mira, conozco a Alice, Alice quiere que entre. Y la única forma en que lo dejarán entrar es si puede demostrar que ese mensaje realmente proviene de Alice. Entonces, para hacer esto, Alice tomará su clave privada y el mensaje que quiere enviar a Bob. En este caso, el mensaje en sí no necesita estar encriptado. Está bien si otras personas pueden leer el mensaje. Y ella generará una firma. Una firma se ve como una salida de hash y es como un galimatías. Es solo una herramienta criptográfica, y veremos cómo usar la firma en un momento.
Y luego genera la firma. Su clave pública es conocida por todos, y ella le envió a Bob el mensaje y la firma. Ahora, Bob quiere poder demostrar que tiene este mensaje de Alice, que realmente proviene de Alice. Entonces puede tomar la clave pública de Alice, el mensaje y la firma, y realizar la verificación criptográfica. Y esto solo devolverá que la verificación tuvo éxito si realmente coinciden la clave pública, la firma, el mensaje, y la clave privada. Entonces, solo alguien con acceso a la clave privada de Alice puede crear una firma que sea verificable con la clave pública de Alice.
Veamos cómo se hace esto en Node.js. Para realizar la firma, Alice leerá su clave privada en la memoria. Tomará el mensaje que desea firmar. Y llamará a crypto.sign, pasando la función hash que se utilizará como parte del proceso de firma, el mensaje y la clave privada. Para realizar la verificación, Bob, o cualquier otra persona, puede tomar el mensaje y la firma, leer la clave pública de Alice, y llamar a crypto.verify, pasando parámetros similares. Y esto solo devolverá verdadero si está verificado si toda la criptografía y las matemáticas coinciden. Otra mención notable aquí, tenemos dentro del módulo crypto una función llamada createHMAC, código de autenticación de mensajes basado en hash.
8. Certificados de Clave Pública y Verificación
Esta es una alternativa para autenticar utilizando certificados de clave pública. Los certificados ayudan a establecer la propiedad de una clave pública, y una tercera parte de confianza como Carol puede verificar la autenticidad de la clave. Alice envía una solicitud de firma de certificado a Carol, quien luego crea una firma utilizando su clave privada. Bob puede verificar el certificado utilizando la firma, los metadatos y la clave pública de Carol. Node.js proporciona la clase de certificado X.509 para este proceso.
Esta es una alternativa para autenticar. Entonces, ¿qué demuestra realmente esto? ¿Qué ganamos cuando introducimos esta firma y verificación? ¿Puede alguien como Bob saber con certeza que el mensaje realmente proviene de Alice? De cierta manera, sí, pero de cierta manera, no. Porque todo esto demuestra es que alguien con una clave privada que coincide con una clave pública de alguien que afirma ser Alice envió ese mensaje. Pero, ¿cómo sabemos que realmente era Alice, la entidad, Alice, la persona que envió ese mensaje? Aquí es donde entran en juego los certificados de clave pública.
Los certificados de clave pública ayudan a establecer la propiedad de una clave pública. Entonces, si Bob quiere recibir un mensaje de Alice y poder saber que realmente proviene de Alice, no hay una solución mágica. Necesitan una tercera parte, alguien que los conozca a ambos, o en quien ambos confíen. Y esta tercera parte ayudará a establecer la confianza entre ellos. Quiero presentarte a Carol, a quien puedes reconocer por su ropa como la hermana de Bob, y también es amiga de Alice. Y ella ayudará en este proceso.
Para demostrar que la clave pública que Alice está utilizando realmente pertenece a Alice de una manera en la que Bob encuentre confiable, Alice utilizará la ayuda de Carol. Creará un borrador de certificado. Este contendrá la clave pública de Alice y algunos metadatos sobre Alice, como su nombre y su país. Y esto es lo que llamamos el TBS a ser firmado. Enviará esto como una solicitud de firma de certificado a Carol. Carol hará su debida diligencia para asegurarse de que esto sea realmente Alice. Y cuando esté satisfecha, creará una firma del TBS utilizando su clave privada. Y luego Alice tomará la firma, y con ella tendrá su certificado final.
Luego, Bob, antes de poder confiar realmente en que esta es la clave pública de Alice, realizará la verificación de manera similar al proceso que mostramos antes utilizando la firma, los metadatos y la clave pública del certificado, pero lo verificará utilizando la clave pública de Carol. Veamos cómo se hace esto en Node.js. Primero, podemos usar la clase de certificado X.509. Este es el nombre del estándar para cómo crear certificados y leer el certificado desde el archivo. Luego, Bob puede leer los metadatos sobre el certificado. ¿Quién es el sujeto? Alice. ¿Quién es el emisor? Carol. ¿Hasta cuándo se debe considerar válido este certificado? Y para realizar la verificación, lo que Bob puede hacer es llamar al certificado de Carol, cargarlo en memoria, que contiene la clave pública de Carol. Y la clave pública de Carol como emisor se puede usar para verificar el certificado de Alice, y solo si esto devuelve verdadero, Bob puede saber que puede confiar en el certificado.
9. Confianza en la Jerarquía de Certificados
Para establecer confianza en el certificado de Carol, Bob puede confiar en el certificado de Doris. La confianza en los certificados se basa en una jerarquía o cadena, donde el certificado superior es confiable porque forma parte del sistema operativo o del navegador.
Ahora, es posible que te preguntes, bueno, está bien. Pero si se utiliza el certificado de Carol en el proceso, ¿cómo puede Bob saber si confiar en el certificado de Carol? Bueno, ¿cómo empiezas a confiar en tu hermana? Lo haces porque tu mamá te lo dice. Así que esta es Doris. Ella es, ya sabes, su mamá. Bob puede usar el certificado de Doris para confiar en el certificado de Carol. Y lo que esto trata de ilustrar realmente es que, una vez más, no hay una solución mágica aquí. Para confiar en un certificado, necesitas confiar en un certificado diferente. Y en la parte superior de esta jerarquía de certificados, o cadena de certificados, hay un certificado en el que simplemente confías porque confías en él, típicamente porque forma parte de tu sistema operativo o navegador. Así que esta es, esta es, esta es, esta es, esta es la información de los certificados de clave pública. Así que esta es toda la información que cubrimos hoy. Gracias por escuchar. Aquí puedes encontrar todo el code de esta charla con los ejemplos que puedes ejecutar. Si quieres saber más sobre las cosas en las que estoy interesado, te animo a seguirme en línea en Twitter o en mi blog. A veces publico sobre proyectos como este, donde tomé una mini máquina arcade y la convertí en un monitor Grafana siempre encendido. Así que si este tipo de proyectos te interesan, puedes echarle un vistazo. Y muchas gracias.
Comments