<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: rooyca</title>
    <description>The latest articles on DEV Community by rooyca (@rooyca).</description>
    <link>https://dev.to/rooyca</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F889554%2F7e1b07e0-233c-43cc-a27f-6df98c959841.png</url>
      <title>DEV Community: rooyca</title>
      <link>https://dev.to/rooyca</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rooyca"/>
    <language>en</language>
    <item>
      <title>HTTP request from Obsidian notes</title>
      <dc:creator>rooyca</dc:creator>
      <pubDate>Sun, 02 Jun 2024 02:59:26 +0000</pubDate>
      <link>https://dev.to/rooyca/http-request-from-obsidian-notes-1j85</link>
      <guid>https://dev.to/rooyca/http-request-from-obsidian-notes-1j85</guid>
      <description>&lt;p&gt;Are you an &lt;a href="https://obsidian.md/"&gt;Obsidian&lt;/a&gt; user looking to elevate your note-taking experience with dynamic data integration? Look no further than APIR (&lt;a href="https://rooyca.github.io/obsidian-api-request/"&gt;api-request&lt;/a&gt;) – an Obsidian plugin designed to streamline HTTP requests directly into your notes.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚡ How to Use
&lt;/h2&gt;

&lt;p&gt;With APIR, integrating HTTP requests into your notes is a breeze. Simply create a code-block within your note, specifying the language as &lt;code&gt;req&lt;/code&gt;. Inside this code-block, customize parameters such as URL, method, body, headers, and more to tailor your request precisely to your needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  👨🏻‍💻 Example Code-block
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;```&lt;/span&gt;&lt;span class="nl"&gt;req
&lt;/span&gt;&lt;span class="sb"&gt;url: https://my-json-server.typicode.com/typicode/demo/comments
method: post
body: {"id":1}
headers: {"Accept": "application/json"}
format: &amp;lt;h1&amp;gt;{}&amp;lt;/h1&amp;gt;
req-id: id-persona
disabled&lt;/span&gt;
&lt;span class="p"&gt;```&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example demonstrates how to send a POST request to a server, displaying the response 'id' field within an HTML heading tag. For more info about all the &lt;code&gt;flags&lt;/code&gt; you can visit &lt;a href="https://rooyca.github.io/obsidian-api-request/"&gt;APIR docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ready to revolutionize your note-taking workflow? &lt;strong&gt;Try APIR today!&lt;/strong&gt; 🌟&lt;/p&gt;




&lt;p&gt;P.S. If you find any bug, have any problem, doubt or want to add any functionality don't hesitate to write me. (You can also leave your issue at &lt;a href="https://github.com/Rooyca/obsidian-api-request/issues"&gt;https://github.com/Rooyca/obsidian-api-request/issues&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>obsidian</category>
      <category>plugin</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Creando un acortador de enlaces en 12 lineas de código usando Cloudflare Workers + Bonus</title>
      <dc:creator>rooyca</dc:creator>
      <pubDate>Sun, 19 Mar 2023 16:32:21 +0000</pubDate>
      <link>https://dev.to/rooyca/creando-un-acortador-de-enlaces-en-12-lineas-de-codigo-usando-cloudflare-workers-bonus-40k1</link>
      <guid>https://dev.to/rooyca/creando-un-acortador-de-enlaces-en-12-lineas-de-codigo-usando-cloudflare-workers-bonus-40k1</guid>
      <description>&lt;p&gt;&lt;strong&gt;Post original &lt;a href="https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/"&gt;aquí&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloudflare Workers
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developers.cloudflare.com/workers/"&gt;Cloudflare Workers&lt;/a&gt;, de forma muy resumida, es un entorno serverless que corre Javascript. Básicamente, escribes código que se ocupa de peticiones HTTP, similar a Node.js. El código es desplegado globalmente en toda la red de Cloudflare, lo que significa que siempre está corriendo lo más cerca posible del usuario final.&lt;/p&gt;

&lt;p&gt;Crear un acortador de enlaces con esta herramienta es muy fácil, aquí un pequeño tutorial de cómo hacerlo.&lt;/p&gt;

&lt;p&gt;Para este proyecto, al ser algo pequeño, con el plan gratis será más que suficiente. Si te interesa hacer algo más grande te vendría bien revisar los planes de pago.&lt;/p&gt;

&lt;h2&gt;
  
  
  KV Storage
&lt;/h2&gt;

&lt;p&gt;Primero, necesitaremos un lugar para almacenar nuestra información. Usaremos &lt;a href="https://developers.cloudflare.com/workers/runtime-apis/kv"&gt;Workers KV&lt;/a&gt;, el cual no es más que un almacenamiento de llave - valor (key-value, en inglés) proporcionado por Cloudflare Workers. Nos dirigimos a &lt;strong&gt;Workers &amp;gt; KV&lt;/strong&gt; damos click en &lt;strong&gt;Create namespace&lt;/strong&gt;. Seleccionamos un nombre y damos click en &lt;strong&gt;Add&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8HFzuYh4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/create-kv-namespace.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8HFzuYh4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/create-kv-namespace.png" title="Create namespace" alt="Screenshot of the ‘Create namespace’ form in Cloudflare dashboard" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Damos click en &lt;strong&gt;View&lt;/strong&gt; en la lista de &lt;em&gt;namespace&lt;/em&gt; para acceder a nuestro nuevo &lt;em&gt;namespace&lt;/em&gt;,  y añadimos algunas entradas. La llave será el "&lt;em&gt;token&lt;/em&gt;" para nuestro enlace corto, y el valor será la URL a la que se redirecionará.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--evsKWLLO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/kv-entries.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--evsKWLLO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/kv-entries.png" title="KV entries" alt="Screenshot of the KV key-value editor UI" width="800" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creando el servicio &lt;em&gt;worker&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Ahora, nos dirigimos a la parte de &lt;strong&gt;Workers &amp;gt; Overview&lt;/strong&gt;, y damos click en &lt;strong&gt;Create a service&lt;/strong&gt;. Escogemos un nombre, seleccionamos la platilla de &lt;strong&gt;HTTP handler&lt;/strong&gt; con el modulo sintaxis, y finalmente damos click en &lt;strong&gt;Create service&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XXDdQb8A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/create-service.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XXDdQb8A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/create-service.png" title="Create a service" alt="Screenshot of the ‘Create a service’ form in Cloudflare dashboard" width="800" height="661"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Debería redireccionarnos a nuestro nuevo servicio:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CJH7lgKe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/worker-service-page.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CJH7lgKe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/worker-service-page.png" title="Service page" alt="Screenshot of the worker service page" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Asignando el KV namespace a una variable
&lt;/h2&gt;

&lt;p&gt;Antes de comenzar a programar, necesitamos asignar nuestro KV namespace a una variable, de tal manera que podamos accederlo desde nuestro código. Vamos a la pestaña de &lt;strong&gt;Settings&lt;/strong&gt;, luego a la sección de &lt;strong&gt;Variables&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--obpSM5q9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/settings-variables.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--obpSM5q9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/settings-variables.png" title="Settings &amp;gt; Variables" alt="Screenshot of the Variables page of the service" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En &lt;strong&gt;KV Namespace Bindings&lt;/strong&gt; damos click en &lt;strong&gt;Add binding&lt;/strong&gt;, ingresamos &lt;code&gt;kv&lt;/code&gt; como nombre de  variable  (tú puedes seleccionar otro nombre, si gustas), seleccionamos el KV namespace que creamos antes, y damos &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NLhK23eq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/kv-namespace-binding.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NLhK23eq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/kv-namespace-binding.png" title="KV namespace binding" alt="Screenshot of the “Add KV namespace binding” form" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  El código
&lt;/h2&gt;

&lt;p&gt;Estamos listo para comenzar a programar! Regresamos a la pestaña de &lt;strong&gt;Resources&lt;/strong&gt;, y damos click en el botón de &lt;strong&gt;Quick edit&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5_2MDBSc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/code-editor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5_2MDBSc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/code-editor.png" title="Code editor" alt="Screenshot of the code editor for the service" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En la izquierda encontramos un simple editor de Javascript, y en la derecha una UI para testear nuestro worker. Puedes enviar peticiones al worker y verificar cómo responde. Esto hará que testear nuestro código sea &lt;em&gt;muy&lt;/em&gt; sencillo!&lt;/p&gt;

&lt;p&gt;Remplazamos el código con el siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Forbidden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Redirecting...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Location&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dest&lt;/span&gt; &lt;span class="p"&gt;}});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rápida explicación del código:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Tenemos dos parámetros:

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;request&lt;/code&gt;, el cual representa la petición HTTP que acabamos de recibir&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;env&lt;/code&gt;, el cual nos da acceso a las variables de entorno y al &lt;em&gt;KV namespace bindings&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;  Solo queremos procesar peticiones del tipo &lt;code&gt;GET&lt;/code&gt;, por lo que respondemos &lt;code&gt;403 Forbidden&lt;/code&gt; si la petición no es tipo &lt;code&gt;GET&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Extraemos la dirección de la URL, y luego tomamos la primera parte de la dirección; este es el token (o llave) para el enlace corto.&lt;/li&gt;
&lt;li&gt;  Accedemos al KV namespace para encontrar nuestra URL de destino, la cual está asociada con nuestro token.&lt;/li&gt;
&lt;li&gt;  Si lo encontramos, respondemos con &lt;code&gt;302 Found&lt;/code&gt; para redireccionar a nuestra URL (esto lo especificamos en el header &lt;code&gt;Location&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;  De lo contrario, respondemos con un &lt;code&gt;404 Not Found&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testeando y desplegando
&lt;/h2&gt;

&lt;p&gt;Puedes hacer un test usando el panel &lt;strong&gt;HTTP&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ORk64R_1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/test-notfound.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ORk64R_1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/test-notfound.png" title="Not found" alt="Screenshot of a request for a non-existing URL token, returning a 404 response" width="800" height="229"&gt;&lt;/a&gt; &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oz43z7HE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/test-found.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oz43z7HE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thomaslevesque.com/2022/11/01/building-a-url-shortener-in-12-lines-of-code-using-cloudflare-workers/test-found.png" title="Found" alt="Screenshot of a request for an existing URL token, returning a 302 response" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez que estamos satisfechos con los resultados y hemos comprobado que todo funciona correctamente podemos desplegar la instancia dando click en el botón de &lt;strong&gt;Save and deploy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Cuando lo hemos desplegado, podemos ingresar la dirección del panel de test directamente en nuestro navegador y nos redireccionará a nuestra URL de destino.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus - Añadiendo un subdominio para nuestro worker
&lt;/h2&gt;

&lt;p&gt;Nos dirigimos a la pestaña de &lt;strong&gt;Triggers&lt;/strong&gt;, damos click en el botón &lt;strong&gt;Add Custom Domain&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I89Kcfdw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1679243345/Blog/Imgs/Cloudflare%2520Worker/Pasted_image_20230319111559_i9ceaq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I89Kcfdw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1679243345/Blog/Imgs/Cloudflare%2520Worker/Pasted_image_20230319111559_i9ceaq.png" alt="Custom domains" width="800" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego ingresamos nuestro subdominio, del tipo &lt;strong&gt;radio.example.com&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W9njpbkQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1679243345/Blog/Imgs/Cloudflare%2520Worker/Pasted_image_20230319111912_lmoppf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W9njpbkQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1679243345/Blog/Imgs/Cloudflare%2520Worker/Pasted_image_20230319111912_lmoppf.png" alt="add subdomain" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y listo, al ingresar a nuestro subdominio con un token valido, nos redireccionará a nuestra URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Acabamos de crear un acortador de enlaces en 12 lineas de código (claro, sin contar los espacios en blanco ni los corchetes) Nada mal. Es bastante minimalista, pero es un buen comienzo. Recordemos que siempre podemos añadir más URL desde el &lt;em&gt;KV editor&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>cloudflare</category>
      <category>workers</category>
      <category>shorter</category>
    </item>
    <item>
      <title>PicoCTF Writeup – Reverse Engineering (asm2)</title>
      <dc:creator>rooyca</dc:creator>
      <pubDate>Thu, 01 Sep 2022 04:21:47 +0000</pubDate>
      <link>https://dev.to/rooyca/picoctf-writeup-reverse-engineering-asm2-1659</link>
      <guid>https://dev.to/rooyca/picoctf-writeup-reverse-engineering-asm2-1659</guid>
      <description>&lt;p&gt;Primeramente me gustaría dejar claro que esta publicación no es más que una traducción. Por lo que todos los creditos van para &lt;a href="https://mregraoncyber.com/author/mregrablog/"&gt;MRegra Silva&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Información:
&lt;/h1&gt;

&lt;p&gt;Nombre de la plataforma: &lt;a href="https://play.picoctf.org/practice/"&gt;PicoCTF&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nombre del reto: &lt;a href="https://play.picoctf.org/practice/challenge/16?page=4"&gt;asm2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Categoría: Ingeniería Inversa&lt;/p&gt;

&lt;p&gt;Puntos: 250&lt;/p&gt;

&lt;p&gt;PicoCTF 2019.&lt;/p&gt;

&lt;h2&gt;
  
  
  Descripción del reto:
&lt;/h2&gt;

&lt;p&gt;¿Qué retorna asm2(0xb, 0x2e)? Envía la bandera como un valor hexadecimal (comienza con '0x'). NOTA: El envío para este reto NO será en el formato normal de las banderas. &lt;a href="https://jupiter.challenges.picoctf.org/static/717467c8c8b4332ea5873ad8fe7b2dad/test.S"&gt;Código&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pista: &lt;a href="https://www.tutorialspoint.com/assembly_programming/assembly_conditions.htm"&gt;Condiciones&lt;/a&gt; en ensamblador&lt;/p&gt;

&lt;h1&gt;
  
  
  Writeup (Inicio)
&lt;/h1&gt;

&lt;p&gt;En este reto, tenemos el código fuente en ensamblador. El archivo se llama &lt;em&gt;test.S&lt;/em&gt; y acontinuación puedes ver el código en cuestion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;asm2:
    &amp;lt;+0&amp;gt;:   push   ebp
    &amp;lt;+1&amp;gt;:   mov    ebp,esp
    &amp;lt;+3&amp;gt;:   sub    esp,0x10
    &amp;lt;+6&amp;gt;:   mov    eax,DWORD PTR [ebp+0xc]
    &amp;lt;+9&amp;gt;:   mov    DWORD PTR [ebp-0x4],eax
    &amp;lt;+12&amp;gt;:  mov    eax,DWORD PTR [ebp+0x8]
    &amp;lt;+15&amp;gt;:  mov    DWORD PTR [ebp-0x8],eax
    &amp;lt;+18&amp;gt;:  jmp    0x509 &amp;lt;asm2+28&amp;gt;
    &amp;lt;+20&amp;gt;:  add    DWORD PTR [ebp-0x4],0x1
    &amp;lt;+24&amp;gt;:  sub    DWORD PTR [ebp-0x8],0xffffff80
    &amp;lt;+28&amp;gt;:  cmp    DWORD PTR [ebp-0x8],0x63f3
    &amp;lt;+35&amp;gt;:  jle    0x501 &amp;lt;asm2+20&amp;gt;
    &amp;lt;+37&amp;gt;:  mov    eax,DWORD PTR [ebp-0x4]
    &amp;lt;+40&amp;gt;:  leave  
    &amp;lt;+41&amp;gt;:  ret 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como dige anteriormente, esto es código en ensamblador, ya solucioné un reto sobre ensamblador por lo que podría ser parecido, vamos a probar.&lt;/p&gt;

&lt;p&gt;Para entender el programa decidí ir línea por línea.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;+0&amp;gt;:   push   ebp
    &amp;lt;+1&amp;gt;:   mov    ebp,esp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como ya sabemos &lt;strong&gt;asm2(0xb, 0x2e)&lt;/strong&gt; está siendo puesto en el &lt;em&gt;stack&lt;/em&gt;. Esto pasa en las primeras dos líneas. La primera hace &lt;em&gt;push&lt;/em&gt; de &lt;strong&gt;asm2&lt;/strong&gt; hacia &lt;strong&gt;ebp&lt;/strong&gt; y después se mueve dicho valor hacia &lt;strong&gt;esp&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Después de estas dos instrucciones, el estado del &lt;em&gt;stack&lt;/em&gt; es el siguiente:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Direccion&lt;/th&gt;
&lt;th&gt;Valor&lt;/th&gt;
&lt;th&gt;Instrucción&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0xc&lt;/td&gt;
&lt;td&gt;0x2e&lt;/td&gt;
&lt;td&gt;ebp+0xc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x8&lt;/td&gt;
&lt;td&gt;0xb&lt;/td&gt;
&lt;td&gt;ebp+0x8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x4&lt;/td&gt;
&lt;td&gt;ret&lt;/td&gt;
&lt;td&gt;ebp+0x4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x0&lt;/td&gt;
&lt;td&gt;ebp&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Saber esto nos ayuda bastante. Ahora vamos a ver la siguiente instrucción:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;+3&amp;gt;:   sub    esp,0x10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En esta instrucción, simplemente estamos a asignando espacio para algunas variables locales, por lo que el stack quedaría así:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Direccion&lt;/th&gt;
&lt;th&gt;Valor&lt;/th&gt;
&lt;th&gt;Instrucción&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0xc&lt;/td&gt;
&lt;td&gt;0x2e&lt;/td&gt;
&lt;td&gt;ebp+0xc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x8&lt;/td&gt;
&lt;td&gt;0xb&lt;/td&gt;
&lt;td&gt;ebp+0x8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x4&lt;/td&gt;
&lt;td&gt;ret&lt;/td&gt;
&lt;td&gt;ebp+0x4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x0&lt;/td&gt;
&lt;td&gt;ebp&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-0x4&lt;/td&gt;
&lt;td&gt;local1&lt;/td&gt;
&lt;td&gt;ebp-0x4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-0x8&lt;/td&gt;
&lt;td&gt;local2&lt;/td&gt;
&lt;td&gt;ebp-0x8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-0xc&lt;/td&gt;
&lt;td&gt;local3&lt;/td&gt;
&lt;td&gt;ebp-0xc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-0x10&lt;/td&gt;
&lt;td&gt;local4&lt;/td&gt;
&lt;td&gt;ebp-0x10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Continuamos con:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;+6&amp;gt;:   mov    eax,DWORD PTR [ebp+0xc]
    &amp;lt;+9&amp;gt;:   mov    DWORD PTR [ebp-0x4],eax
    &amp;lt;+12&amp;gt;:  mov    eax,DWORD PTR [ebp+0x8]
    &amp;lt;+15&amp;gt;:  mov    DWORD PTR [ebp-0x8],eax
    &amp;lt;+18&amp;gt;:  jmp    0x509 &amp;lt;asm2+28&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos instrucción por instruccion:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Primero, le asignamos al registro &lt;strong&gt;eax&lt;/strong&gt; el valor de &lt;strong&gt;ebp+0xc&lt;/strong&gt; que sería &lt;strong&gt;0x2e&lt;/strong&gt;, según el &lt;em&gt;stack&lt;/em&gt; actual.&lt;/li&gt;
&lt;li&gt;Después, movemos el valor del registro &lt;strong&gt;eax&lt;/strong&gt; a ebp-0x4, que en nuestro caso sería &lt;strong&gt;local1&lt;/strong&gt;, es decír la variable &lt;strong&gt;local1&lt;/strong&gt; tendría el valor &lt;strong&gt;0x2e&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Luego movemos el contenido de &lt;strong&gt;epb+0x8&lt;/strong&gt; a &lt;strong&gt;eax&lt;/strong&gt;, es decír, su valor sería &lt;strong&gt;0xb&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;En la linea +15 movemos el contenido del registro &lt;strong&gt;eax&lt;/strong&gt; hacia &lt;strong&gt;ebp-0x8&lt;/strong&gt;, es decír la variable &lt;strong&gt;local2&lt;/strong&gt; tendría el valor &lt;strong&gt;0xb&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Finalmente hacemos un salto hacia &lt;strong&gt;asm2+28&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;El estado actual del &lt;em&gt;stack&lt;/em&gt; es:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Direccion&lt;/th&gt;
&lt;th&gt;Valor&lt;/th&gt;
&lt;th&gt;Instrucción&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0xc&lt;/td&gt;
&lt;td&gt;0x2e&lt;/td&gt;
&lt;td&gt;ebp+0xc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x8&lt;/td&gt;
&lt;td&gt;0xb&lt;/td&gt;
&lt;td&gt;ebp+0x8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x4&lt;/td&gt;
&lt;td&gt;ret&lt;/td&gt;
&lt;td&gt;ebp+0x4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x0&lt;/td&gt;
&lt;td&gt;ebp&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-0x4&lt;/td&gt;
&lt;td&gt;0x2e&lt;/td&gt;
&lt;td&gt;ebp-0x4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-0x8&lt;/td&gt;
&lt;td&gt;0xb&lt;/td&gt;
&lt;td&gt;ebp-0x8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-0xc&lt;/td&gt;
&lt;td&gt;local3&lt;/td&gt;
&lt;td&gt;ebp-0xc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-0x10&lt;/td&gt;
&lt;td&gt;local4&lt;/td&gt;
&lt;td&gt;ebp-0x10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Pasemos a la siguiente instrucción:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;+28&amp;gt;:  cmp    DWORD PTR [ebp-0x8],0x63f3
    &amp;lt;+35&amp;gt;:  jle    0x501 &amp;lt;asm2+20&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como sabrás, la anterior instrucción nos hizo saltar hacia &lt;strong&gt;asm2+28&lt;/strong&gt;, la cual es una comparación seguida de un salto si el resultado es menor o igual que. En este caso, comparamos &lt;strong&gt;ebp-0x8&lt;/strong&gt; (es decir, la variable &lt;strong&gt;local2&lt;/strong&gt; que tiene el valor &lt;strong&gt;0xb&lt;/strong&gt;) y &lt;strong&gt;0x63f3&lt;/strong&gt;. Sabemos que &lt;strong&gt;0xb&lt;/strong&gt; es menor que &lt;strong&gt;0x63f3&lt;/strong&gt; por lo que hacemos el salto hacia &lt;strong&gt;asm2+20&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;+20&amp;gt;:  add    DWORD PTR [ebp-0x4],0x1
    &amp;lt;+24&amp;gt;:  sub    DWORD PTR [ebp-0x8],0xffffff80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En la linea +20 tenemos una istrucción &lt;em&gt;add&lt;/em&gt;, añadimos 1 a &lt;strong&gt;ebp-0x4&lt;/strong&gt;, convirtiéndolo en &lt;strong&gt;0x2f&lt;/strong&gt;.&lt;br&gt;
En la linea +24 tenemos una instrucción &lt;em&gt;sub&lt;/em&gt;, restamos &lt;strong&gt;0xffffff80&lt;/strong&gt; a &lt;strong&gt;ebp-0x8&lt;/strong&gt;. Esto es x86 por lo que tenemos que truncar el resultado, para ello simplemente realizamos esta operación en Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;local2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mh"&gt;0xffffff80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0xffffffff&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora el valor de &lt;em&gt;local2&lt;/em&gt; es: &lt;strong&gt;0x8b&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Continuando con la siguiente linea nos encontramos nuevamente en la +28 y sabemos que &lt;strong&gt;0x8b&lt;/strong&gt; es menor que &lt;strong&gt;0x63f3&lt;/strong&gt; por lo que volvemos a dar el salto. Para facilitar el proceso creé un &lt;em&gt;script&lt;/em&gt; en Python que no es más que una "traducción" de este código en ensamblador. El &lt;em&gt;script&lt;/em&gt; en cuestión es el siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt;
Stack:
[  local4 ]  &amp;lt;--- ebp-0x10
[  local3 ]  &amp;lt;--- ebp-0xc
[  local2 ]  &amp;lt;--- ebp-0x8
[  local1 ]  &amp;lt;--- ebp-0x4
[   ebp   ]
[   ret   ]  &amp;lt;--- ebp+0x4
[   arg1  ]  &amp;lt;--- ebp+0x8
[   arg2  ]  &amp;lt;--- ebp+0xc
&lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;
&lt;span class="c1"&gt;#We know that asm2 receives two arguments
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;asm2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="c1"&gt;#asm2:
&lt;/span&gt;    &lt;span class="c1"&gt;#&amp;lt;+0&amp;gt;:  push   ebp
&lt;/span&gt;    &lt;span class="c1"&gt;#&amp;lt;+1&amp;gt;:  mov    ebp,esp
&lt;/span&gt;    &lt;span class="c1"&gt;#&amp;lt;+3&amp;gt;:  sub    esp,0x10
&lt;/span&gt;
    &lt;span class="c1"&gt;#&amp;lt;+6&amp;gt;:  mov    eax,DWORD PTR [ebp+0xc]
&lt;/span&gt;    &lt;span class="n"&gt;eax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt;

    &lt;span class="c1"&gt;#&amp;lt;+9&amp;gt;:  mov    DWORD PTR [ebp-0x4],eax
&lt;/span&gt;    &lt;span class="n"&gt;local1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eax&lt;/span&gt;

    &lt;span class="c1"&gt;#&amp;lt;+12&amp;gt;: mov    eax,DWORD PTR [ebp+0x8]
&lt;/span&gt;    &lt;span class="n"&gt;eax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;

    &lt;span class="c1"&gt;#&amp;lt;+15&amp;gt;: mov    DWORD PTR [ebp-0x8],eax
&lt;/span&gt;    &lt;span class="n"&gt;local2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eax&lt;/span&gt;

    &lt;span class="c1"&gt;#&amp;lt;+18&amp;gt;: jmp    0x509 &amp;lt;asm2+28&amp;gt;
&lt;/span&gt;    &lt;span class="c1"&gt;#&amp;lt;+20&amp;gt;: add    DWORD PTR [ebp-0x4],0x1
&lt;/span&gt;    &lt;span class="c1"&gt;#&amp;lt;+24&amp;gt;: sub    DWORD PTR [ebp-0x8],0xffffff80
&lt;/span&gt;    &lt;span class="c1"&gt;#&amp;lt;+28&amp;gt;: cmp    DWORD PTR [ebp-0x8],0x63f3
&lt;/span&gt;    &lt;span class="c1"&gt;#&amp;lt;+35&amp;gt;: jle    0x501 &amp;lt;asm2+20&amp;gt;
&lt;/span&gt;    &lt;span class="nf"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local2&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mh"&gt;0x63f3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;local1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0xffffffff&lt;/span&gt;              &lt;span class="c1"&gt;#This truncates the result to 32 bits.
&lt;/span&gt;        &lt;span class="n"&gt;local2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mh"&gt;0xffffff80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0xffffffff&lt;/span&gt;    &lt;span class="c1"&gt;#This truncates the result to 32 bits.           
&lt;/span&gt;    &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt;
       It is necessary to truncate the restuls because in python does not have
       buffer overflow but 0x86 can have so we have to truncate it.
       &lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;

    &lt;span class="c1"&gt;#&amp;lt;+37&amp;gt;: mov    eax,DWORD PTR [ebp-0x4]
&lt;/span&gt;    &lt;span class="c1"&gt;#&amp;lt;+40&amp;gt;: leave
&lt;/span&gt;    &lt;span class="c1"&gt;#&amp;lt;+41&amp;gt;: ret
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;asm2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x2e&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como dige anteriormente, el &lt;em&gt;script&lt;/em&gt; es una "traducción" como hice antes pero con sintáxis de Python 3. Después de ejecutar el código obtendremos la bandera.&lt;/p&gt;




&lt;p&gt;Espero les haya sido de tanta utilidad como a mí, cualquier duda no &lt;em&gt;duden&lt;/em&gt; en enviarme un mensaje.&lt;/p&gt;

&lt;p&gt;Link del post original: &lt;a href="https://mregraoncyber.com/picoctf-writeup-asm2/"&gt;https://mregraoncyber.com/picoctf-writeup-asm2/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>picoctf</category>
      <category>asm</category>
      <category>writeup</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Enviar correos desde Gmail usando tu propio dominio</title>
      <dc:creator>rooyca</dc:creator>
      <pubDate>Sun, 17 Jul 2022 22:03:21 +0000</pubDate>
      <link>https://dev.to/rooyca/enviar-correos-desde-gmail-usando-tu-propio-dominio-599</link>
      <guid>https://dev.to/rooyca/enviar-correos-desde-gmail-usando-tu-propio-dominio-599</guid>
      <description>&lt;p&gt;¿Cansado de pagarle a tu proveedor mes a mes para poder usar tu(s) correo(s)? Pues ya no más porque hoy aprenderemos a configurar nuestras cuentas de correo con Gmail en cuatro sencillos pasos.&lt;/p&gt;

&lt;h1&gt;
  
  
  Primero - Redireccionar el trafico
&lt;/h1&gt;

&lt;p&gt;Lo primero que debemos hacer es redireccionar el trafico de nuestro cuenta de correo electrónico (en este caso &lt;a href="mailto:me@rooyca.xyz"&gt;me@rooyca.xyz&lt;/a&gt;) hacia Gmail. Para ello vamos a nuestro proveedor de dominio o nuestro CDN de preferencia, en mi caso CloudFlare. Ahora nos dirigimos a la parte de &lt;em&gt;Email&lt;/em&gt; &amp;gt; &lt;em&gt;Routes&lt;/em&gt; &amp;gt; &lt;em&gt;Create address&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---aPuPaPQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_972/v1657979535/Blog/Imgs/domain-gmail/13_fmzgzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---aPuPaPQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_972/v1657979535/Blog/Imgs/domain-gmail/13_fmzgzs.png" alt="Create Cuenta" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creamos nuestra dirección apuntando al Gmail con el que vamos a configurar nuestra cuenta. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tcTcicbt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_972/v1657979535/Blog/Imgs/domain-gmail/14_sfypei.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tcTcicbt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_972/v1657979535/Blog/Imgs/domain-gmail/14_sfypei.png" alt="Apuntando cuenta" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Listo, con esto habríamos finalizado el primer paso. Ahora mismo deberíamos estar recibiendo todos los correos enviados al correo que configuramos (en mi caso &lt;em&gt;&lt;a href="mailto:me@rooyca.xyz"&gt;me@rooyca.xyz&lt;/a&gt;&lt;/em&gt;) en nuestra cuenta de Gmail. Es recomendable ensayar que todo está funcionando correctamente enviándote un correo desde otra cuenta. Si todo funciona de manera correcta continuamos. (Si presentas algún inconveniente no dudes en dejarme un comentario).&lt;/p&gt;

&lt;h1&gt;
  
  
  Segundo - Creando la contraseña
&lt;/h1&gt;

&lt;p&gt;A continuación necesitaremos crear las credenciales con las que ingresaremos más tarde. Para ello damos clic en nuestra imagen de perfil y después en &lt;em&gt;Gestionar tu cuenta de Google&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LY29RF4h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_972/v1657979532/Blog/Imgs/domain-gmail/1_ebmiie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LY29RF4h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_972/v1657979532/Blog/Imgs/domain-gmail/1_ebmiie.png" alt="Gestionar Cuenta" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos a la pestaña de &lt;em&gt;Seguridad&lt;/em&gt;, en el panel de la izquierda y bajamos un poco hasta encontrar la opción &lt;em&gt;Contraseñas de aplicaciones&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FXc95FoM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_972/v1657979531/Blog/Imgs/domain-gmail/3_kvt0qx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FXc95FoM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_972/v1657979531/Blog/Imgs/domain-gmail/3_kvt0qx.png" alt="Contra" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creamos unas nuevas credenciales. En tipo ponemos &lt;em&gt;correo&lt;/em&gt; y en dispositivo ponemos &lt;em&gt;otra&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K9nT7kdr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979532/Blog/Imgs/domain-gmail/4_mlc6mf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K9nT7kdr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979532/Blog/Imgs/domain-gmail/4_mlc6mf.png" alt="Credenciales" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora ponemos la cuenta que creamos en el paso uno.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qIbVDo12--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979532/Blog/Imgs/domain-gmail/5_gnv9s1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qIbVDo12--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979532/Blog/Imgs/domain-gmail/5_gnv9s1.png" alt="Credenciales 2" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Listo, se generarán nuestras credenciales, guárdalas en algún lugar porque las necesitaremos más adelante.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zezuidhr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979532/Blog/Imgs/domain-gmail/6_avvqqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zezuidhr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979532/Blog/Imgs/domain-gmail/6_avvqqr.png" alt="Credenciales final" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Tercero - Importando nuestra cuenta
&lt;/h1&gt;

&lt;p&gt;Ahora nos vamos a &lt;em&gt;configuración&lt;/em&gt; &amp;gt; &lt;em&gt;ver todos los ajustes&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t26LGpdA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_972/v1657979534/Blog/Imgs/domain-gmail/7_v5e61b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t26LGpdA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_972/v1657979534/Blog/Imgs/domain-gmail/7_v5e61b.png" alt="Ver ajustes" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Después nos dirigimos a &lt;em&gt;Cuentas e importación&lt;/em&gt; &amp;gt; &lt;em&gt;Añadir otra dirección de correo electrónico&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cKHXBl-_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979534/Blog/Imgs/domain-gmail/8_ihlv58.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cKHXBl-_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979534/Blog/Imgs/domain-gmail/8_ihlv58.png" alt="Añadir cuenta" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nos aparecerá una ventana emergente en la que debemos ingresar el nombre de nuestra cuenta (el que aparecerá cuando enviemos un correo) y nuestra dirección de correo creada en el primer paso. Es importante asegurarnos de que la opción &lt;em&gt;Tratar como alias&lt;/em&gt; está deshabilitada.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--64zVUa14--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_972/v1657979535/Blog/Imgs/domain-gmail/9_fq5rqa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--64zVUa14--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_972/v1657979535/Blog/Imgs/domain-gmail/9_fq5rqa.png" alt="configuramos" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aquí es IMPORTANTE ingresar:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;smtp.google.com&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En la parte de &lt;em&gt;Servidor SMTP&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;En &lt;em&gt;Nombre de usuario&lt;/em&gt; ponemos la cuenta de gmail que estamos usando pero sin el &lt;strong&gt;&lt;em&gt;@gmail.com&lt;/em&gt;&lt;/strong&gt;, en mi caso sería &lt;em&gt;rooyca&lt;/em&gt;. Por último, en contraseña ingresamos la que creamos en el anterior paso. Lo demás lo dejamos tal cual está.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j4q7ZtlU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979534/Blog/Imgs/domain-gmail/10_iexzfy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j4q7ZtlU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979534/Blog/Imgs/domain-gmail/10_iexzfy.png" alt="Ingresar contraseña" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Después de dar en añadir cuenta nos aparecerá una ventana en la que nos pedirá un código de verificación. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FqegdgLG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979536/Blog/Imgs/domain-gmail/11_kg2zfo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FqegdgLG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979536/Blog/Imgs/domain-gmail/11_kg2zfo.png" alt="verificación " width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Revisamos nuestro bandeja de entrada y deberíamos tener un coreo con el código de verificación y un enlace para completar la verificación.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tL3LqPzk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657984028/Blog/Imgs/domain-gmail/16_dihmfj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tL3LqPzk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657984028/Blog/Imgs/domain-gmail/16_dihmfj.png" alt="Correo verificación" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copiamos y pegamos el código en la ventana. Y después damos click en el enlace.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jaS_HmwO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_972/v1657984258/Blog/Imgs/domain-gmail/17_dedyye.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jaS_HmwO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_972/v1657984258/Blog/Imgs/domain-gmail/17_dedyye.png" alt="Copiar y pegar" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se nos abriría una nueva pestaña en la que confirmaremos que deseamos enviar correos con la cuenta que creamos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HzkPVCrD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979531/Blog/Imgs/domain-gmail/18_hyncia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HzkPVCrD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979531/Blog/Imgs/domain-gmail/18_hyncia.png" alt="Confirmar" width="800" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si nos dirigimos a la parte de &lt;em&gt;Redactar&lt;/em&gt; podremos observar que ya podemos enviar correos desde nuestra dirección.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c7Pj7pyD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979533/Blog/Imgs/domain-gmail/20_hqp1wp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c7Pj7pyD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1657979533/Blog/Imgs/domain-gmail/20_hqp1wp.png" alt="Prueba" width="608" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y eso sería todo, así de fácil es configurar una dirección de correo con nuestro dominio. Recuerda, si tienes alguna duda, queja, sugerencia o reclamo no dudes en hacérmela saber.&lt;/p&gt;

&lt;p&gt;PD: Disculpas por la calidad de las imágenes :(&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Discord&lt;/strong&gt;: rooyca#6075&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telegram&lt;/strong&gt;: @seiseiseis&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gmail</category>
      <category>cloudflare</category>
      <category>domain</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Alojar Wordpress en la nube (Google Cloud)</title>
      <dc:creator>rooyca</dc:creator>
      <pubDate>Sat, 09 Jul 2022 22:05:16 +0000</pubDate>
      <link>https://dev.to/rooyca/alojar-wordpress-en-la-nube-google-cloud-29gi</link>
      <guid>https://dev.to/rooyca/alojar-wordpress-en-la-nube-google-cloud-29gi</guid>
      <description>&lt;p&gt;¿Has pensado en alojar tu sitio con WordPress en la nube, pero no sabes cómo? Hoy aprenderemos juntos el proceso para correr nuestro sitio en Google Cloud, pero un proceso similar podría utilizarse para correrlo en cualquier otra plataforma como AWS o Azure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xgKJo7UA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://upload.wikimedia.org/wikipedia/commons/2/20/WordPress_logo.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xgKJo7UA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://upload.wikimedia.org/wikipedia/commons/2/20/WordPress_logo.svg" alt="Wordpress" width="540" height="123"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Creando la Máquina Virtual
&lt;/h1&gt;

&lt;p&gt;"WordPress es un sistema de gestión de contenidos lanzado el 27 de mayo de 2003, enfocado a la creación de cualquier tipo de página web". Según estas veinte &lt;a href="https://blog.hubspot.com/website/wordpress-stats#:~:text=(W3Techs%2C%202022),every%20five%20websites%20use%20WordPress."&gt;estadísticas&lt;/a&gt; sobre WordPress para el 2022 encontramos que WordPress es usado por el 43.2% de todas las páginas en Internet.&lt;/p&gt;

&lt;p&gt;Para poder correr WordPress en Google Cloud (GCloud de ahora en adelante), primeramente debemos crear una máquina virtual con una de las imágenes con las que cuenta GCloud. Para ello vamos a la parte superior izquierda, damos clic en "Más Productos" y buscamos "Marketplace". &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--znTnZglC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656712908/Blog/Imgs/hosting%2520wordpress/1_hjegaj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--znTnZglC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656712908/Blog/Imgs/hosting%2520wordpress/1_hjegaj.png" alt="Una" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se nos abrirá una ventana en la que buscaremos WordPress y le daremos a la primera opción (openlitespeed-wordpress)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C6haV7Tv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656710344/Blog/Imgs/hosting%2520wordpress/3_o7rjwl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C6haV7Tv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656710344/Blog/Imgs/hosting%2520wordpress/3_o7rjwl.png" alt="Dos" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A continuación vamos a darle a "Iniciar", después de esto se nos abrirá una ventana en la que podremos modificar las características que tendrá nuestra máquina virtual, mi recomendación es que la dejemos tal como se ve en la siguiente imagen (por supuesto escogiendo un nombre diferente). Todo lo demás que no se alcanza a ver en la imagen es porque deberemos dejarlo tal cual está. Presionamos, aceptar Términos y Condiciones y luego crear.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bEfRfn6M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656710344/Blog/Imgs/hosting%2520wordpress/5_lbdvbs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bEfRfn6M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656710344/Blog/Imgs/hosting%2520wordpress/5_lbdvbs.png" alt="Tres" width="800" height="652"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y listo, eso sería todo, ya tenemos configurada nuestra máquina virtual. El resultado final debería ser algo como lo siguiente:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A3ATa8Cb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656711028/Blog/Imgs/hosting%2520wordpress/6_tcnjcy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A3ATa8Cb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656711028/Blog/Imgs/hosting%2520wordpress/6_tcnjcy.png" alt="Cuatro" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Iniciando sesión en nuestra MV
&lt;/h1&gt;

&lt;p&gt;Para poder completar la instalación de WordPress y demás complemento en nuestra máquina virtual, es necesario completar una serie de pasos.&lt;/p&gt;

&lt;p&gt;Primeramente, debemos instalar Google Cloud CLI, en el siguiente &lt;a href="https://cloud.google.com/sdk/docs/install"&gt;link&lt;/a&gt; encontrarás una guía completa con todo el proceso, pero si lo que deseas es únicamente instalarlo puedes abrir una Power Shell como Administrador y ejecutar el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(New-Object Net.WebClient).DownloadFile("https://dl.google.com/dl/cloudsdk/channels/rapid/GoogleCloudSDKInstaller.exe", "$env:Temp\GoogleCloudSDKInstaller.exe")

&amp;amp; $env:Temp\GoogleCloudSDKInstaller.exe
    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una vez hecho esto e instalado el CLI vamos a Inicio y buscamos "gcloud" abrimos el primer resultado y ejecutamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud auth login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se abrirá una ventana del navegador en la que tendremos que escoger nuestra cuenta de Google con la que creamos la máquina virtual. Damos aceptar a todo y listo.&lt;/p&gt;

&lt;p&gt;Una vez la consola nos diga que estamos logeados de manera exitosa tendremos que correr el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud compute ssh --zone "TU_ZONA" "NOMBRE_MAQUINA_VIRTUAL"  --project "NOMBRE_PROYECTO"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nos abrirá una ventana en la que deberemos ingresar nuestro dominio y un correo para poder configurar el SSL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zCLbpynk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656711850/Blog/Imgs/hosting%2520wordpress/7_se6twg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zCLbpynk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656711850/Blog/Imgs/hosting%2520wordpress/7_se6twg.png" alt="Cinco" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Después de realizar este proceso nos dirigimos a:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="http://NUESTRA_IP/wp-admin"&gt;http://NUESTRA_IP/wp-admin&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Para instalar WordPress.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---nXUiJNH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656712691/Blog/Imgs/hosting%2520wordpress/8_dmaxmo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---nXUiJNH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656712691/Blog/Imgs/hosting%2520wordpress/8_dmaxmo.png" alt="Seis" width="800" height="871"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  "Aumentando" la memoria RAM
&lt;/h1&gt;

&lt;p&gt;Es muy poca la memoria RAM que configuramos para nuestra máquina virtual, por lo que es altamente recomendable hacer Swap. "El Swap es el espacio que el disco duro tiene para intercambiar la memoria física con la memoria virtual". Para ello vamos a ejecutar los siguientes comandos, en orden:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo fallocate -l 1GB /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
free -m

#Para que cuando se reinicie el servidor conservemos el archivo SWAP
echo '/swapfile none swap sw 00' | sudo tee -a /etc/fstab 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y eso sería todo, así de sencillo es correr WordPress en Google Cloud.&lt;/p&gt;

&lt;p&gt;Recuerden que si tienen alguna duda pueden escribirme por: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;   Discord: rooyca#6075&lt;/li&gt;
&lt;li&gt;   Telegram: @seiseiseis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hasta la próxima. Que tengan un excelente día.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>googlecloud</category>
      <category>db</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Hacer Deploy de FastAPI y Celery (con RabbitMQ y PostgreSQL) en Heroku</title>
      <dc:creator>rooyca</dc:creator>
      <pubDate>Sat, 09 Jul 2022 22:05:02 +0000</pubDate>
      <link>https://dev.to/rooyca/hacer-deploy-de-fastapi-y-celery-con-rabbitmq-y-postgresql-en-heroku-1d9k</link>
      <guid>https://dev.to/rooyca/hacer-deploy-de-fastapi-y-celery-con-rabbitmq-y-postgresql-en-heroku-1d9k</guid>
      <description>&lt;p&gt;Como ya es conocido por todos, plataformas como Heroku y Netlify nos permiten desplegar nuestros proyectos y páginas web sin costo alguno. El día de hoy haremos uso de Heroku para desplegar un &lt;a href="https://letbxl.herokuapp.com/docs"&gt;proyecto&lt;/a&gt; de Scraping hecho con FastAPI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6ZO0iZqZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656265660/Blog/Imgs/Celery%252C%2520FastAPI%2520en%2520Heroku/Screenshot_at_2022-06-26_12-47-22_zk3uxw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6ZO0iZqZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656265660/Blog/Imgs/Celery%252C%2520FastAPI%2520en%2520Heroku/Screenshot_at_2022-06-26_12-47-22_zk3uxw.png" alt="DOCS" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Heroku
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://heroku.com/"&gt;Heroku&lt;/a&gt; es una Plataforma como Servicio (PaaS) que le permite a los desarrollados construir, ejecutar y operar aplicaciones enteramente en la Nube.&lt;/p&gt;

&lt;p&gt;Heroku cuenta (a la fecha) con cuatro planes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gratis

&lt;ul&gt;
&lt;li&gt;Aplicaciones no comerciales, pruebas de concepto y proyectos personales.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Producción ($25 o más)

&lt;ul&gt;
&lt;li&gt;Aplicaciones de negocios, tales como Aplicaciones y Apis internas de empresas.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Avanzado ($250 o más)

&lt;ul&gt;
&lt;li&gt;Aplicaciones con funcionalidades complejas que requieren alta disponibilidad, muy poca latencia y manejo de altos volúmenes de peticiones.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Empresa (Precio por definir)

&lt;ul&gt;
&lt;li&gt;Aplicaciones de organizaciones a gran escala.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Más &lt;a href="//heroku.com/pricing"&gt;información&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Scraping con FastAPI
&lt;/h1&gt;

&lt;p&gt;Uno de los problemas que encontré a lo largo del desarrollo de este proyecto fue el de los tiempos de respuesta. Cuando se hace una petición a la API para que obtenga la información de una lista de Letterboxd, dicho proceso puede tomar algunos segundos, incluso minutos. El problema radica en que el servidor se queda "pegado" tratando de responder a la solicitud por lo que no es posible realizar una nueva petición. Como podrán imaginar, esperar hasta UN minuto por solicitud no es nada practico ni agradable, por lo que aquí es donde entra Celery y RabbitMQ.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LY608A_J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656267002/Blog/Imgs/Celery%252C%2520FastAPI%2520en%2520Heroku/asyncVsyncD_wbhy05.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LY608A_J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656267002/Blog/Imgs/Celery%252C%2520FastAPI%2520en%2520Heroku/asyncVsyncD_wbhy05.png" alt="SynYAsync" width="565" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En la pagina oficial de &lt;a href="https://docs.celeryq.dev/en/stable/"&gt;Celery&lt;/a&gt; encontramos lo siguiente:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Celery is a simple, flexible, and reliable distributed system to process vast amounts of messages, while providing operations with the tools required to maintain such a system. It’s a task queue with focus on real-time processing, while also supporting task scheduling.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Y en la página de &lt;a href="https://www.rabbitmq.com/"&gt;RabbitMQ&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;RabbitMQ is a messaging broker - an intermediary for messaging. It gives your applications a common platform to send and receive messages, and your messages a safe place to live until received.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En pocas palabras, y con posibilidades de caer en equivocaciones, podríamos decir que Celery se encarga del manejo de las solicitudes para que estas puedan procesarse en "segundo plano" y así liberar el End Point para continuar recibiendo peticiones. Esto se logra -a muy grandes rasgos- asignándole una ID a la tarea, esta ID es la respuesta de esa primera petición. Con dicha ID podemos, en otro End Point, estar pendientes de nuestra tarea, cuando ya esté lista recibiremos el JSON de la lista de películas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FLVoZr5C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656264521/Blog/Imgs/Celery%252C%2520FastAPI%2520en%2520Heroku/Screenshot_at_2022-06-26_12-28-21_ooxezx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FLVoZr5C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656264521/Blog/Imgs/Celery%252C%2520FastAPI%2520en%2520Heroku/Screenshot_at_2022-06-26_12-28-21_ooxezx.png" alt="Response" width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora bien, entonces ¿cuál es la función de RabbitMQ en todo esto? &lt;/p&gt;

&lt;p&gt;"Sencillo", RabbitMQ lo que hace es almacenar la solicitud y la respuesta que genera Celery.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;De las dos definiciones anteriores ruego se tome en serio muy poco de lo expuesto y en lugar aconsejo que se haga una investigación por cuenta propia.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Dónde correr RabbitMQ?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FDNFj_rj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_400%2Cz_1.5/v1656263933/Blog/Imgs/Celery%252C%2520FastAPI%2520en%2520Heroku/RabbitMQ_logo_njq6vk.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FDNFj_rj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_400%2Cz_1.5/v1656263933/Blog/Imgs/Celery%252C%2520FastAPI%2520en%2520Heroku/RabbitMQ_logo_njq6vk.svg" alt="Rabbit" width="172" height="27"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para esto encontré dos opciones: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Google Cloud o cualquier plataforma similar (AWZ, Azure, etc.)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devcenter.heroku.com/articles/cloudamqp"&gt;CloudAMQP&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En este caso vamos a utilizar la primer opción, pero si deseas probar la segunda puedes dar click en el enlace de arriba y encontrarás una guía completa.&lt;/p&gt;

&lt;p&gt;La pregunta es, ¿cómo hice para correr RabbitMQ con Google CLoud? Fácil, hice uso de Contenedores. Primero busqué la imagen de RabbitMQ para posteriormente correrla... todo muy sencillo hasta ahí.&lt;/p&gt;

&lt;p&gt;El problema vino a la hora de tratar de obtener una IP externa. Lo que hice fue lo siguiente. En la consola de Google Cloud corrí:&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;Remplazando todo lo que está completamente en Mayúsculas&lt;/strong&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gcloud container clusters get-credentials [NOMBRE_CLUSTER] --zone [ZONA_CLUSTER]&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Después, para exponer el servicio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl patch service/SERVICO_NOMBRE-rabbitmq-svc \
  --namespace default \
  --patch '{"spec": {"type": "LoadBalancer"}}'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por último, para obtener la IP externa y los puertos:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl get service SERVICO_NOMBRE-rabbitmq-svc&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo correr Celery en Heroku?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LoaMPbXu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_102/v1656263916/Blog/Imgs/Celery%252C%2520FastAPI%2520en%2520Heroku/celery_512_n1acnv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LoaMPbXu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/c_scale%2Cw_102/v1656263916/Blog/Imgs/Celery%252C%2520FastAPI%2520en%2520Heroku/celery_512_n1acnv.png" alt="Celery" width="102" height="102"&gt;&lt;/a&gt;&lt;br&gt;
Como sabrán, a la hora de correr un APP en Heroku necesitamos un archivo llamado &lt;em&gt;Procfile&lt;/em&gt; en el que le especificamos a Heroku los comando que se ejecutarán a la hora de iniciar la aplicación.&lt;/p&gt;

&lt;p&gt;Entonces, para poder ejecutar FastAPI y Celery a la vez necesitamos que nuestro archivo &lt;em&gt;Procfile&lt;/em&gt; luzca algo así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;web: gunicorn -w 3 -k uvicorn.workers.UvicornWorker main:app
worker: celery -A main.celery worker -Q letterboxList

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Donde &lt;em&gt;main&lt;/em&gt; hace referencia al nombre del archivo principal.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;app y celery&lt;/em&gt; hacen referencia al nombre de las variables dentro del &lt;em&gt;main&lt;/em&gt; archivo que se encargan de iniciar FastAPI y Celery, respectivamente.&lt;/li&gt;
&lt;li&gt;Por último, &lt;em&gt;letterboxList&lt;/em&gt; hace referencia al nombre de la tarea.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ya para finalizar, en mi caso tuve que realizar un paso más. &lt;/p&gt;

&lt;p&gt;Tuve que dirigirme a la página de &lt;a href="https://heroku.com"&gt;Heroku&lt;/a&gt;, seleccionar el APP que había creado, darle en &lt;em&gt;Resources&lt;/em&gt; y revisar que los dos Dynos estuvieran activados. En mi caso el de &lt;em&gt;worker&lt;/em&gt; no lo estaba así que tuve que darle al icono del Lápiz (la opción de editar Dyno) y activarlo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fhJubjTr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656264842/Blog/Imgs/Celery%252C%2520FastAPI%2520en%2520Heroku/Screenshot_at_2022-06-26_12-32-37_llrzqi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fhJubjTr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1656264842/Blog/Imgs/Celery%252C%2520FastAPI%2520en%2520Heroku/Screenshot_at_2022-06-26_12-32-37_llrzqi.png" alt="OneMore" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y eso sería todo, así de sencillo es correr FastAPI y Celery en Heroku. Por último, si desean ver el resultado final de este proyecto pueden dar click &lt;a href="https://letbxl.herokuapp.com/docs"&gt;aquí&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Recuerden que si tienen alguna duda pueden escribirme por: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;   Discord: rooyca#6075&lt;/li&gt;
&lt;li&gt;   Telegram: @seiseiseis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hasta la próxima. Que tengan un excelente día.&lt;/p&gt;

</description>
      <category>heroku</category>
      <category>fastapi</category>
      <category>rabbitmq</category>
      <category>celery</category>
    </item>
    <item>
      <title>Como extraer la obra completa de Shakespeare de una Imagen</title>
      <dc:creator>rooyca</dc:creator>
      <pubDate>Sat, 09 Jul 2022 22:04:06 +0000</pubDate>
      <link>https://dev.to/rooyca/como-extraer-la-obra-completa-de-shakespeare-de-una-imagen-4gn5</link>
      <guid>https://dev.to/rooyca/como-extraer-la-obra-completa-de-shakespeare-de-una-imagen-4gn5</guid>
      <description>&lt;p&gt;¿Te gustaría leer la obra completa de uno de los grandes de la literatura inglesa pero piensas que es demasiado extensa como para descargarla? Pues el día de hoy te tengo la solución, vamos a extraérla desde una pequeña imagen (2 Megabytes) con su rostro...&lt;/p&gt;

&lt;h1&gt;
  
  
  Esteganografía
&lt;/h1&gt;

&lt;h2&gt;
  
  
  ¿Qué es?
&lt;/h2&gt;

&lt;p&gt;A diferencia de la criptografía, donde es obvio que se está ocultando algo, la esteganografía oculta la información de tal forma que no se levante sospechas de que hay algo oculto. Esto se consigue por medio de diferentes técnicas que nos permiten ocultar archivos, imágenes, textos o incluso vídeos dentro de otros archivos.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo funciona?
&lt;/h2&gt;

&lt;p&gt;Hay diferentes técnicas para ocultar información dentro de archivos. Una de las más usadas y quizás la más sencilla de entender es la comúnmente conocido como "Técnica del Bit menos significante" o LSB (por sus siglas en inglés).&lt;/p&gt;

&lt;p&gt;Esta técnica lo que hace es cambiar algunos de los últimos bits en un byte para codificar el mensaje. Esto es útil en imágenes, donde el valor del rojo, verde y azul están representados por bits (un byte) en un rango de 0 a 255 (ver &lt;a href="https://en.wikipedia.org/wiki/RGB"&gt;RGB&lt;/a&gt;) en decimales o de 00000000 a 11111111 en binario.&lt;/p&gt;

&lt;p&gt;Cambiar el valor de los últimos dos bits en un pixel completamente rojo de: 11111111 a 11111101 unicamente cambia el valor de rojo de 255 a 253, lo cual a simple vista crea un cambio prácticamente imperceptible, pero que aún así nos permite ocultar información dentro de la imagen. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r1KIOV5P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632442360/Blog/Imgs/steganography/lsb_drvccm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r1KIOV5P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632442360/Blog/Imgs/steganography/lsb_drvccm.jpg" alt="LSB" width="800" height="480"&gt;&lt;/a&gt;&lt;br&gt;
El anterior diagrama muestra dos imágenes de 4 pixeles cada una, junto a su respectivo valor binario. (&lt;a href="https://null-byte.wonderhowto.com/how-to/steganography-hide-secret-data-inside-image-audio-file-seconds-0180936/"&gt;Fuente&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Como dijimos anteriormente, esta técnica funciona muy bien con archivos multimedia, pero no tanto con archivos de texto ASCII donde un simple bit puede cambiar los caracteres completamente. Sin mencionar que el LSB es la técnica más sencilla de detectar.&lt;/p&gt;
&lt;h2&gt;
  
  
  ¿Cómo usarla?
&lt;/h2&gt;

&lt;p&gt;Recuerda que hay muchas técnicas de esteganografía, unas mejores que otras. Por lo general lo mejor es evitar la LSB e ir por algo un poco más sofisticado. Incluso, ¿por qué no?, diseñar tu propio algoritmo de esteganografía.&lt;/p&gt;

&lt;p&gt;También es importante tener presentes los conceptos de encriptar y comprimir. Si encriptamos la información antes de ocultarla le añadimos una capa más de seguridad, mientras que comprimir la información nos permitirá añadirle más información a nuestro archivo.  &lt;/p&gt;

&lt;p&gt;Para el desarrollo de este tutorial, vamos a utilizar Steghide, una herramienta sencilla de usar pero no por ello menos eficaz. &lt;/p&gt;
&lt;h3&gt;
  
  
  1. Ocultando información
&lt;/h3&gt;

&lt;p&gt;Primeramente vamos a instalar Steghide, por medio de apt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;steghide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una vez instalado procemos a ocultar nuestra información, con el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;steghide embed &lt;span class="nt"&gt;-ef&lt;/span&gt; archivoSecreto &lt;span class="nt"&gt;-cf&lt;/span&gt; archivoDePortada &lt;span class="nt"&gt;-sf&lt;/span&gt; archivoFinal &lt;span class="nt"&gt;-z&lt;/span&gt; nivelDeCompresion &lt;span class="nt"&gt;-e&lt;/span&gt; esquema
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora vamos a explicar los argumentos que acabamos de utilizar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;-ef&lt;/strong&gt; especifica la ruta del archivo que queremos ocultar. Podemos ocultar cualquier tipo de archivos dentro de nuestro archivo, incluyento scripts en Python.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-cf&lt;/strong&gt; este es el archivo en el cual ocultaremos nuestra información. Aquí si hay restricciones, solo se permiten archivos del tipo BMP, JPEG, WAV y AU.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-sf&lt;/strong&gt; es un argumento opcional que especifica el nombre del archivo resultante de esta "unión". Si no lo especificamos el archivo original será sobrescrito. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-z&lt;/strong&gt; especifica el nivel de compresión, en un rango de 1 a 9. Si prefiere no comprimir su archivo use el argumente &lt;strong&gt;-Z&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-e&lt;/strong&gt; especifica el tipo de encriptación. Steghide soporta una gran cantidad de esquemas de encriptación y si se omite este argumento Steghide usará la opción por defecto que es 128-bit AES. Si prefieres no usar encriptacion simplemtente escribe &lt;strong&gt;-e none&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En el siguiente ejemplo, ocultaré un archivo de texto dentro de una imagen de un tierno cachorro (para levantar menos sospecha 😉). El archivo final se llamará "perrito-secreto.jpeg", no voy a hacer uso del compresor ni del encriptador, y el comando en la terminal luciría algo así:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;steghide embed -ef secret.txt -cf perrito.jpeg -sf perrito-secreto.jpeg -e none -Z&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Después de ingresar nuestro comando Steghide nos pedirá que le asignemos una contraseña a nuestro archivo. Una vez ingresamos la passphrase tendremos nuestro archivo con información confidencial dentro de él 😄.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uiG8kQxl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632446520/Blog/Imgs/steganography/info-ocul_d2mpa7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uiG8kQxl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632446520/Blog/Imgs/steganography/info-ocul_d2mpa7.png" alt="PERRITO-SEC" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El resultado sería una imagen común y corriente... Si deseas saber lo que hay dentro del archivo de texto, aquí te dejo la imagen (password: topsecret):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YaDeLEZx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632446478/Blog/Imgs/steganography/perrito-secreto_xgzjlc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YaDeLEZx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632446478/Blog/Imgs/steganography/perrito-secreto_xgzjlc.jpg" alt="PERRITO" width="474" height="632"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Extrayendo información
&lt;/h3&gt;

&lt;p&gt;El proceso de extraer la información de nuestros archivos es incluso más sencillo. El comando que deberemos ejecutar es el siguiente:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;steghide extract -sf archivoSecreto -xf archivoFinal&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Cuando ejecutamos este comando nos pedirá la contraseña, la ingresamos y deberíamos tener todos los archivos que se encontraban dentro del &lt;code&gt;archivoSecreto&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ahora bien, te estarás preguntando, ¿cómo hago para extraer información de un archivo si no tengo la contraseña? Pues actualmente existen infinidad de herramientas que nos pueden ayudar con eso. Pero el día de hoy vamos a hacer uso de &lt;a href="https://github.com/ReFirmLabs/binwalk/tree/master"&gt;&lt;strong&gt;binwalk&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Como lo prometí en un principio, vamos a extraer la obra completa de Shakespeare de la siguiente imagen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r6vTdVY1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632447298/Blog/Imgs/steganography/shakespeare_hempxe.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r6vTdVY1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632447298/Blog/Imgs/steganography/shakespeare_hempxe.jpg" alt="SHAKESPEARE" width="64" height="64"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O si prefieres puedes visitar el post original en &lt;a href="https://twitter.com/David3141593/status/1058124224798380032"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Al correr nuestro binwalk (&lt;code&gt;binwalk shakespeare.jpg&lt;/code&gt;) nos indica que la imagen esta compuesta de 31 archivos RAR. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ianyXMyW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632447713/Blog/Imgs/steganography/data-shake_ta3h6y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ianyXMyW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632447713/Blog/Imgs/steganography/data-shake_ta3h6y.png" alt="DATA-SP" width="800" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Procedemos a extraer los archivos de la siguiente manera &lt;br&gt;
&lt;code&gt;binwalk  -e -C ./shake shakespeare.jpeg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9TyHBsz4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632448228/Blog/Imgs/steganography/final-html_ios0md.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9TyHBsz4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632448228/Blog/Imgs/steganography/final-html_ios0md.png" alt="FILEs" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lo que creará una carpeta "shake" en nuestro directorio actual. Al ejecutar el comando nos extraerá los 31 archivos RAR, y al extraer el primero de ellos(&lt;code&gt;shakespeare.-part001.rar&lt;/code&gt;) nos quedará un último archivo llamado &lt;code&gt;shakespeare.html&lt;/code&gt; que al abrirlo, nos saldrá algo así:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RkkgQNnu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632448228/Blog/Imgs/steganography/html1_az1vsv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RkkgQNnu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632448228/Blog/Imgs/steganography/html1_az1vsv.png" alt="FILES-FINAL" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¿Increíble no?&lt;/p&gt;

&lt;p&gt;Bueno, eso sería todo por el día de hoy. Si quieres expander tus conocimientos sobre este tema te recomiendo leer &lt;a href="https://linuxhint.com/hide_files_inside_images_linux/"&gt;este&lt;/a&gt; y &lt;a href="https://ostechnix.com/hide-files-inside-images-linux/"&gt;este&lt;/a&gt; articulo. ¿Eso no es suficiente? Te recomiendo &lt;a href="https://academy.hoppersroppers.org/course/view.php?id=7#section-4"&gt;este&lt;/a&gt; curso de CTF, que abarca estos temas y muchos más. Y recuerda, si tienes alguna duda, queja, sugerencia o reclamo no dudes en hacérmelo saber.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Discord&lt;/strong&gt;: rooyca#6075&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telegram&lt;/strong&gt;: @seiseiseis&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>steganography</category>
      <category>linux</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Una guía para compartir archivos en la Blockchain con IPFS</title>
      <dc:creator>rooyca</dc:creator>
      <pubDate>Sat, 09 Jul 2022 21:43:23 +0000</pubDate>
      <link>https://dev.to/rooyca/una-guia-para-compartir-archivos-en-la-blockchain-con-ipfs-2j28</link>
      <guid>https://dev.to/rooyca/una-guia-para-compartir-archivos-en-la-blockchain-con-ipfs-2j28</guid>
      <description>&lt;p&gt;Antes de nada, ¿qué es IPFS? La descripción oficial que encontramos en su sitio &lt;a href="https://ipfs.io/"&gt;web&lt;/a&gt; es la siguiente:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Un protocolo hypermedia &lt;a href="https://es.wikipedia.org/wiki/Peer-to-peer"&gt;peer-to-peer&lt;/a&gt; diseñado para preservar y hacer crecer el conocimiento de la humanidad haciendo la web más abierta, más resiliente y mejor.&lt;/p&gt;



&lt;p&gt;IPFS, o Interplanetary File System, creado por Protocol Labs, es un protocolo peer-to-peer donde cada nodo almacena una colección de archivos &lt;em&gt;hasheados&lt;/em&gt;. Un usuario que desee alguno de esos archivos se conecta a una capa de este protocolo y por medio del Hash, IPFS se encarga "recolectar" el archivo que está distribuido a través de los nodos y finalmente envía el archivo al usuario que lo solicitó.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vpxxhUEo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://205324-619698-raikfcquaxqncofqfm.stackpathdns.com/wp-content/uploads/2019/06/IPFS-Advantages-Cover-1-1130x570.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vpxxhUEo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://205324-619698-raikfcquaxqncofqfm.stackpathdns.com/wp-content/uploads/2019/06/IPFS-Advantages-Cover-1-1130x570.png" alt="IPFS-IMG" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fuente: &lt;a href="https://radiostud.io/"&gt;https://radiostud.io/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;¿Recuerdan BitTorrent? Pues es parecido, solo que con IPFS tienes más control de tus archivos y se hace referencia a tus archivos por medio de hashes.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Y la seguridad?
&lt;/h3&gt;

&lt;p&gt;Como habrán podido deducir, en IPFS "cualquiera" puede tener acceso a nuestros archivos, lo único que se necesita es un Hash del tipo: &lt;em&gt;QmYqSCWuzG8Cyo4MFQzqKcC14ct4ybA&lt;/em&gt;... para descargar nuestro archivo. Lo que nos llevaría a concluir que IPFS no es el protocolo indicado para archivos "sensibles"... ¿o sí?&lt;/p&gt;

&lt;h3&gt;
  
  
  Con ustedes, Encriptación Asimétrica (EA)
&lt;/h3&gt;

&lt;p&gt;Por suerte, contamos con herramientas que nos permiten asegurar nuestros archivos antes de subirlos a IPFS. La EA nos permite encriptar el archivo con la clave publica del destinatario, lo que garantiza que terceros no puedan hacer nada con el archivo. Para este tutorial usaremos &lt;a href="https://www.gnupg.org/"&gt;GPG&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Manos a la obra
&lt;/h3&gt;

&lt;p&gt;En este tutorial, haremos lo siguiente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configurar GPG.&lt;/li&gt;
&lt;li&gt;Configurar IPFS.&lt;/li&gt;
&lt;li&gt;Encriptar un archivo con la clave publica de alguien.&lt;/li&gt;
&lt;li&gt;Subir un archivo encriptado a IPFS.&lt;/li&gt;
&lt;li&gt;Descargar dicho archivo desde otra máquina y asegurarnos de que solo el destinatario pueda ver su contenido.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Instalación de lo que usaremos
&lt;/h3&gt;

&lt;h4&gt;
  
  
  GPG
&lt;/h4&gt;

&lt;p&gt;Tendremos que descargar GPG en ambas maquinas, la que envía y la que recibe, para ello nos dirigimos a &lt;a href="//blog.ghostinthemachines.com/2015/03/01/how-to-use-gpg-command-line/"&gt;este&lt;/a&gt; link y seguimos las instrucciones dependiendo de nuestro sistema operativo. Una vez instalado vamos a generar una clave en ambos equipos, para ello usamos el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gpg &lt;span class="nt"&gt;--gen-key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luego nos pedirá nuestro nombre, correo, un comentario y una contraseña, que entre más robusta mejor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6QC45_hH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1633438176/Blog/Imgs/IPFS/publickey_rxodzo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6QC45_hH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1633438176/Blog/Imgs/IPFS/publickey_rxodzo.png" alt="IMG-KEY" width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora, en nuestro segundo equipo, después de generada la clave, la vamos a exportar con el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gpg &lt;span class="nt"&gt;--export&lt;/span&gt; &lt;span class="nt"&gt;--armor&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; clavePublica.asc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pasamos nuestro archivo a nuestro segundo pc, e importamos la clave con el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gpg &lt;span class="nt"&gt;--import&lt;/span&gt; clavePublica.asc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos revisar nuestras claves con el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gpg &lt;span class="nt"&gt;--list-keys&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Listo, eso sería todo en cuanto a GPG, ahora vamos a configurar nuestro nodo.&lt;/p&gt;

&lt;h4&gt;
  
  
  IPFS
&lt;/h4&gt;

&lt;p&gt;Existen varias alternativas a la hora de descargar IPFS, en el siguiente &lt;a href="https://ipfs.io/#install"&gt;enlace&lt;/a&gt; podremos usar la que nos parezca mejor. En mi caso usaré la terminal, una vez instalado podremos iniciar nuestro nodo con el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ipfs init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recuerda que esto debes hacerlo en ambos computadores. Después de esto deberemos iniciar nuestro programa (&lt;em&gt;daemon&lt;/em&gt;: Disk And Execution MONitor)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ipfs daemon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zmaacwU9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1633439020/Blog/Imgs/IPFS/ipfsdaemon_tbrs3o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zmaacwU9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1633439020/Blog/Imgs/IPFS/ipfsdaemon_tbrs3o.png" alt="IPFS-DAEMON" width="800" height="637"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y listo, ya tendríamos nuestros nodos preparados para subir y bajar archivos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Encriptando nuestro archivo con GPG
&lt;/h3&gt;

&lt;p&gt;Ahora vamos a encripar nuestro archivo para que solo pueda ser desencriptado por el receptor, para ello vamos a correr el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gpg &lt;span class="nt"&gt;--encrypt&lt;/span&gt; &lt;span class="nt"&gt;--recipient&lt;/span&gt; &lt;span class="s2"&gt;"Nombre del que recibe"&lt;/span&gt; archivo.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En el que podrán notar dos variables, el nombre de la persona que lo recibe (que debe ser el mismo que pusimos en la clave pública que generamos anteriormente), en mi caso seria "Rooyca" y después pondremos nuestro archivo, que en mi caso es un pdf. Nos quedará un archivo con extensión .gpg.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w-gFYkl7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1633439717/Blog/Imgs/IPFS/encrypt_gqawej.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w-gFYkl7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1633439717/Blog/Imgs/IPFS/encrypt_gqawej.png" alt="ENCRYP" width="800" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Subiéndolo a IPFS
&lt;/h3&gt;

&lt;p&gt;Una vez que tenemos todo preparado podemos abrir nuestra terminal y subir nuestro archivo encriptado a IPFS con el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ipfs add archivo.pdf.gpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5o9sfucZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1633440055/Blog/Imgs/IPFS/ipfsadd_diqry9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5o9sfucZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1633440055/Blog/Imgs/IPFS/ipfsadd_diqry9.png" alt="IPFS-ADD" width="739" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos comprobar que subimos correctamente nuestro archivo con el comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ipfs pin &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QDRFozTL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1633440758/Blog/Imgs/IPFS/Untitlead_esz4mb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QDRFozTL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1633440758/Blog/Imgs/IPFS/Untitlead_esz4mb.png" alt="IPFS-LS" width="735" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aquí debemos buscar el Hash que coincida con el resultado de nuestro comando anterior, en mi caso seria:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;QmazcLvRjPMLY5UAGEDVLrJCKX3ySqb8TZxLmvt7pfbxgf&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Descargando de IPFS
&lt;/h3&gt;

&lt;p&gt;Ahora, para descargar nuestro archivo es igual de sencillo, en nuestro segundo computador ingresamos &lt;code&gt;ipfs get&lt;/code&gt; junto al hash del archivo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ipfs get QmazcLvRjPMLY5UAGEDVLrJCKX3ySqb8TZxLmvt7pfbxgf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ya tendriamos nuestro PDF, pero si intentamos abrirlo nos daremos cuenta que no es posible ver su contenido, por lo que procedemos a desencriptarlo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Desencriptando
&lt;/h3&gt;

&lt;p&gt;Para ello vamos a ingresar el siguiente comando, en el que le pasamos el nombre del archivo y "&amp;gt;" para cambiarle el nombre a "archivodes.pdf".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gpg &lt;span class="nt"&gt;--decrypt&lt;/span&gt; QmazcLvRjPMLY5UAGEDVLrJCKX3ySqb8TZxLmvt7pfbxgf &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; archivodes.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y listo, si ahora lo volvemos a abrir podremos acceder de manera normal a nuestro pdf. Así de sencillo es mandar archivos confidenciales o sensibles a través de una excelente plataforma como es IPFS. &lt;/p&gt;

&lt;p&gt;Bueno, eso es todo por hoy, espero que esta pequeña guía los haya animado a mantener su propio nodo y ha hacer uso de este grandioso protocolo. Como siempre, si tienen alguna duda o simplemente desean decirme algo no duden en contactarme.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Discord&lt;/strong&gt;: rooyca#6075&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telegram&lt;/strong&gt;: @seiseiseis&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Publicación original
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://blockgeni.com/a-guide-to-securely-share-files-on-the-blockchain-with-ipfs/"&gt;Blockgeni.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ipfs</category>
      <category>blockchain</category>
      <category>linux</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Crea tu primera API con FLASK</title>
      <dc:creator>rooyca</dc:creator>
      <pubDate>Sat, 09 Jul 2022 21:39:55 +0000</pubDate>
      <link>https://dev.to/rooyca/crea-tu-primera-api-con-flask-1ej4</link>
      <guid>https://dev.to/rooyca/crea-tu-primera-api-con-flask-1ej4</guid>
      <description>&lt;p&gt;El día de hoy vamos a ver cómo crear una sencilla API con Flask. Este es un proyecto que a primera vista parece complicado, pero ya cuando iniciamos nos damos cuenta de que es todo lo contrario; muy sencillo y divertido de realizar, así que te invito a alistar tu IDE y manos a la obra.&lt;/p&gt;

&lt;p&gt;Antes que nada, aqui te dejo el &lt;a href="https://github.com/Rooyca/API-LoRFinder"&gt;link&lt;/a&gt; por si deseas clonar directamente el repositorio de Github.&lt;/p&gt;

&lt;h1&gt;
  
  
  Desarollando nuestra API
&lt;/h1&gt;

&lt;p&gt;Para este tutorial vamos a utilizar principalmente el "Mini"-Framework Flask y algunas extenciones del mismo. Para la instalación de todos los paquetes me gustaria dejarte dos opciones:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Instalar los siguientes paquetes con el comando &lt;code&gt;pip install x-paquete&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;flask&lt;/li&gt;
&lt;li&gt;flask_restful&lt;/li&gt;
&lt;li&gt;&lt;p&gt;flask_sqlalchemy&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Descargar el el archivo &lt;a href="https://github.com/Rooyca/API-LoRFinder/blob/main/requirements.txt"&gt;&lt;code&gt;requirements.txt&lt;/code&gt;&lt;/a&gt; e instalar todo de una vez con el comando &lt;code&gt;pip install -r requirements.txt&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;La primera opcion nos permite ir familiarizandonos poco a poco con las herramientas que vamos utilizando a lo largo de este tutorial y la segunda nos agiliza el trabajo. &lt;/p&gt;

&lt;p&gt;¿Cuál usar? Depende de... &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AyAc5wR8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632278025/Blog/Imgs/Website%2520and%2520Api%2520with%2520Flask%2520%2528LoR%2529/lor_gi6hgv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AyAc5wR8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632278025/Blog/Imgs/Website%2520and%2520Api%2520with%2520Flask%2520%2528LoR%2529/lor_gi6hgv.jpg" alt="YOU-LOR" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Estructura de nuestra API
&lt;/h2&gt;

&lt;p&gt;Vamos a explicar de manera súper básica la estructura de nuestra API. Para mayor informacion te invito a visitar la documentacion oficial de &lt;a href="https://flask-restful.readthedocs.io/en/latest/"&gt;FlaskRESTful&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="mf"&gt;1.&lt;/span&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;
&lt;span class="mf"&gt;2.&lt;/span&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask_restful&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Api&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;marshal_with&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;
&lt;span class="mf"&gt;3.&lt;/span&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask_sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SQLAlchemy&lt;/span&gt;

&lt;span class="mf"&gt;4.&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mf"&gt;5.&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mf"&gt;6.&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SQLALCHEMY_DATABASE_URI&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sqlite:///Players.db&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="mf"&gt;7.&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SQLAlchemy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En las lineas uno, dos y tres importamos Flask, algunas clases desde flask_restful y SQLAlchemy, que será la encargada de realizar las conexiones con nuestra base de datos. Depués, de la linea cuatro a siete realizamos la configuracion de nuestra aplicacion y establecemos una conexion a través de &lt;code&gt;sqlite&lt;/code&gt; con nuestra base de datos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Players&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;__tablename__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;players&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nullable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nullable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;puuid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nullable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;resource_fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;region&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;puuid&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aquí primero creamos la clase &lt;code&gt;Players&lt;/code&gt; que será la encargada de manejar la "extructura" de nuestra base de datos. Como podemos ver, creamos una tabla llamada &lt;code&gt;players&lt;/code&gt; y cuatro columnas. Por último creamos un diccionario llamado &lt;code&gt;resource_fields&lt;/code&gt; para serializar nuestra informacion de tal manera que podamos mostrarla en formato JSON. (¿Qué es &lt;a href="https://es.wikipedia.org/wiki/JSON"&gt;JSON&lt;/a&gt;?)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nd"&gt;@marshal_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource_fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Players&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&amp;lt;string:name&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por último, creamos la clase Player que organizará los datos de nuestra base de datos de la forma en que le especificamos en nuestro diccionario &lt;code&gt;resource_fields&lt;/code&gt;. Luego definimos una función &lt;strong&gt;get&lt;/strong&gt; que tomará como argumantos &lt;em&gt;self&lt;/em&gt; y el nombre del jugador del cual queremos conocer la información. Con estos datos hacemos un &lt;code&gt;query&lt;/code&gt; a nuestra base de datos, diciéndole que nos muestre el primer el primer jugador llamado &lt;code&gt;name&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;api.add_resource(Player, "/&amp;lt;string:name&amp;gt;")&lt;/code&gt; es una de las partes fundamentales de nuestro código, pues es aquí donde especificamos la ruta a la cual se hará la request, o dicho de otra forma, es aquí donde definimos nuestro Endpoint. En este caso sería simplemente a la ruta de inicio, es decir:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;https://0.0.0.0:8000/Bluegod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por último, la parte de &lt;code&gt;if __name__ == "__main__":&lt;/code&gt; sencillamente evita que se ejecute la aplicación cuando es importada por otro script y en la parte de &lt;code&gt;app.run(host='0.0.0.0')&lt;/code&gt; podriamos añadirle &lt;code&gt;debug=True&lt;/code&gt; para que cada que realizamos un cambio y tenemos nuestra aplicación corriendo este cambio se aplica inmediatamente después de guardar, esto ayuda mucho cuando estamos testeando o añadiendo nuevas funciones, pero se recomienda quitarlo a la hora de hacer &lt;em&gt;deploy&lt;/em&gt; de nuestra App.&lt;/p&gt;

&lt;p&gt;Y... ya, eso sería todo, si hemos seguido correctamente todos los pasos hasta aquí deberiamos tener nuestra API funcionando. ¡Vamos a probarla! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9hFmXCvZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632289004/Blog/Imgs/Website%2520and%2520Api%2520with%2520Flask%2520%2528LoR%2529/json_vvz4hc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9hFmXCvZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632289004/Blog/Imgs/Website%2520and%2520Api%2520with%2520Flask%2520%2528LoR%2529/json_vvz4hc.png" alt="RESULTADO-JSON" width="640" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¡Excelente! Sí funciona. &lt;/p&gt;

&lt;p&gt;Bueno, eso sería todo por el día de hoy. Si quieres probar esta API &lt;a href="https://lor-finder.herokuapp.com/"&gt;AQUÍ&lt;/a&gt; te dejo un link en el cual podras hacerlo. Y recuerda, si tienes alguna duda, queja, sugerencia o reclamo no dudes en hacérmelo saber.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Discord&lt;/strong&gt;: rooyca#6075&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telegram&lt;/strong&gt;: @seiseiseis&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>flask</category>
      <category>api</category>
      <category>spanish</category>
      <category>game</category>
    </item>
    <item>
      <title>Creando nuestros comandos personalizados en Linux</title>
      <dc:creator>rooyca</dc:creator>
      <pubDate>Sat, 09 Jul 2022 21:34:29 +0000</pubDate>
      <link>https://dev.to/rooyca/creando-nuestros-comandos-personalizados-en-linux-40e5</link>
      <guid>https://dev.to/rooyca/creando-nuestros-comandos-personalizados-en-linux-40e5</guid>
      <description>&lt;p&gt;¿Cansando de tener que escribir veinte variables para ejecutar un simple comando? Pues hoy aprenderemos a mapear nuestros comandos haciendo uso de &lt;strong&gt;Alias&lt;/strong&gt;. &lt;/p&gt;

&lt;h1&gt;
  
  
  Creando nuestros Aliases
&lt;/h1&gt;

&lt;p&gt;Alias es una forma sencilla de mapper, bindear, unir(?) comandos. Esta es la mejor manera de ahorrarnos tiempo a la hora de escribir cadenas larguísimas de comandos. Si nosotros escribimos "alias" en nuestra terminal debería aparecernos los aliases predeterminados de nuestro sistema, algo así:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I6O0LCJK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632189896/Blog/Imgs/Commands-Linux/alias-predeterminados_lhjdfr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I6O0LCJK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632189896/Blog/Imgs/Commands-Linux/alias-predeterminados_lhjdfr.png" alt="ALIASES-DEFAULT" width="577" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como podran notar, en mi caso tengo dos alias customizados: &lt;strong&gt;price&lt;/strong&gt; y &lt;strong&gt;subl&lt;/strong&gt;; el primero es un script en python que uso para ver el comportamiento del mercado crypto y el segundo es simplemtente para abrir SublimeText. &lt;/p&gt;

&lt;h3&gt;
  
  
  Modificando nuestro archivo .bashrc
&lt;/h3&gt;

&lt;p&gt;Para poder lograr que nuestros alias sean permanentes y no solo durante una seccion de la terminal debemos modificar un archivo llamado .bashrc, que por lo general se encuentra en &lt;em&gt;/home/usuario/&lt;/em&gt; para esto debemos abrirlo con el editor de texto de nuestra preferencia, en mi caso voy a utilizar vim:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vim ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gOVTVwyz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632190837/Blog/Imgs/Commands-Linux/vim-aliases_wgtx0d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gOVTVwyz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632190837/Blog/Imgs/Commands-Linux/vim-aliases_wgtx0d.png" alt="VIM-ALIASES" width="800" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bajamos hasta encontrar la seccion de Aliases y añadimos nuestro comando de la siguiente manera:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias nuestro-comando='comando-a-mapear'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Un ejemplo más claro sería el siguiente:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias price='python3 ~/Desktop/get_price.py'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;En donde "price" es el comando que le quiero asignar a la cadena: "python3 ~/Desktop/get_price.py". Ahora lo último que nos queda es guardar los cambias y listo, así de sencillo tenemos nuestro comando personalizado. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RGFJfqXx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632191334/Blog/Imgs/Commands-Linux/get-price_mntpwd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RGFJfqXx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/rooyca/image/upload/v1632191334/Blog/Imgs/Commands-Linux/get-price_mntpwd.png" alt="GET-PRICE" width="439" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Eso sería todo, si tienen alguna duda no duden en hacermelo saber. &lt;/p&gt;

</description>
      <category>linux</category>
      <category>spanish</category>
    </item>
  </channel>
</rss>
