<?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>Forem: Luis Bastidas</title>
    <description>The latest articles on Forem by Luis Bastidas (@bastiasa).</description>
    <link>https://forem.com/bastiasa</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%2F3709539%2F578126c8-a789-410f-a8aa-d83b10b6e0c7.png</url>
      <title>Forem: Luis Bastidas</title>
      <link>https://forem.com/bastiasa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bastiasa"/>
    <language>en</language>
    <item>
      <title>Hackers don't have to be too smart unless you use this</title>
      <dc:creator>Luis Bastidas</dc:creator>
      <pubDate>Tue, 03 Mar 2026 23:24:08 +0000</pubDate>
      <link>https://forem.com/bastiasa/hackers-doesnt-have-to-be-too-smart-unless-you-do-this-2f8o</link>
      <guid>https://forem.com/bastiasa/hackers-doesnt-have-to-be-too-smart-unless-you-do-this-2f8o</guid>
      <description>&lt;p&gt;I wanted to share a cool and easy system to make your applications safer.&lt;/p&gt;

&lt;p&gt;This tutorial is focused on WebSocket-like systems, but you can apply the same concept elsewhere. The idea is universal.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Main Issue
&lt;/h2&gt;

&lt;p&gt;If you have a WebSocket server, you've probably asked yourself:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How does the server know if a client is from your application and not some wacky person who just spun up a WebSocket client at 3 am and is now knocking on your door? (knock knock, twin)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Good news: there are several ways to handle this. Let me introduce &lt;strong&gt;nonce signature verification&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;You define a &lt;strong&gt;secret key&lt;/strong&gt; that only your application and your server know. Think of it as a shared password that never actually travels through the wire.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Secret key: XDDCC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When a client connects to the server, the server generates and sends a &lt;strong&gt;nonce&lt;/strong&gt;, which is a random blob of bytes that's only valid once (hence the name).&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nonce: emEdkZ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The client must then &lt;strong&gt;sign&lt;/strong&gt; the nonce using the secret key via HMAC-SHA256:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;Nonce&lt;/th&gt;
&lt;th&gt;Signature&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;XDDC&lt;/td&gt;
&lt;td&gt;emEdkZ&lt;/td&gt;
&lt;td&gt;&lt;code&gt;89sWB9akORcl41J0Xh6jNFvawiA8io2s64Cc0NYn1Rs=&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hello world&lt;/td&gt;
&lt;td&gt;emEdkZ&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Mgv5AF+1EdyU2OfzDfyF+63lyWPxdy8iBPNVbGiYJ6U=&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XDDC&lt;/td&gt;
&lt;td&gt;Supa secret nonce&lt;/td&gt;
&lt;td&gt;&lt;code&gt;L/3PcSXooCr6PwmD2exX+xGbMCZB2vyDuKAaMOIxHIc=&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;twin ts is tuff&lt;/td&gt;
&lt;td&gt;Supa secret nonce&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UHmxTyntKFu6ADo3HwbQ+4QMTzjZJXgNps9O5YxurIk=&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice how every change, whether in the key or in the nonce, produces a completely different signature. You can try it yourself &lt;a href="https://www.devglan.com/online-tools/hmac-sha256-online" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The server then verifies that the received signature matches what it would have computed with its own copy of the secret.&lt;/p&gt;
&lt;h3&gt;
  
  
  When does the server kick someone out?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The client takes too long to respond with the signature (timeout = suspicious).&lt;/li&gt;
&lt;li&gt;The signature doesn't match what the server expected.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  In those cases, the server closes the connection. If the client insists on being sketchy, it can escalate with rate limiting or a temporary restriction.
&lt;/h2&gt;
&lt;h2&gt;
  
  
  Why not just send the secret key directly?
&lt;/h2&gt;

&lt;p&gt;Because if the key travels over the network, it can be intercepted via a &lt;a href="https://www.ibm.com/think/topics/man-in-the-middle" rel="noopener noreferrer"&gt;Man-in-the-Middle attack&lt;/a&gt;. Someone sitting between your client and server could just read it.&lt;/p&gt;

&lt;p&gt;By the way twin, this does not replace TLS. Always use WSS in production.&lt;/p&gt;

&lt;p&gt;With nonce-based signing, the secret never leaves the application. Only the derived signature does — and without the original key, that signature is useless to an attacker.&lt;/p&gt;


&lt;h2&gt;
  
  
  Vulnerabilities
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The secret key isn't secret (Wth twin?)
&lt;/h3&gt;

&lt;p&gt;If you implement this in a public application or a video game client, a determined person could extract the secret key from your files. Reverse engineering tools exist and people &lt;em&gt;will&lt;/em&gt; use them.&lt;/p&gt;

&lt;p&gt;
  Fixes
  &lt;ul&gt;
&lt;li&gt;Don't hardcode the secret key in plain text.&lt;/li&gt;
&lt;li&gt;Cipher and obfuscate your application's binaries and assets.
&lt;/li&gt;
&lt;/ul&gt;




&lt;/p&gt;

&lt;h3&gt;
  
  
  Brute Force Attacks
&lt;/h3&gt;

&lt;p&gt;An attacker could intercept a valid signature produced by your application and try every possible key combination until they find one that reproduces it. Of course this is almost impossible, but it's not impossible.&lt;/p&gt;

&lt;p&gt;
  Fix
  &lt;ul&gt;
&lt;li&gt;Rotate the secret key weekly or monthly. This limits how long a cracked key remains useful, turning a catastrophic breach into a minor inconvenience.
&lt;/li&gt;
&lt;/ul&gt;




&lt;/p&gt;

&lt;div class="crayons-card c-embed"&gt;

   &lt;strong&gt;Summary&lt;/strong&gt;: Never transmit your secret. Have the server challenge clients with a random nonce, verify the HMAC signature, and rotate keys regularly. It's simple, battle-tested, and keeps the riffraff out. 
&lt;/div&gt;



</description>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Now this is how you create video games</title>
      <dc:creator>Luis Bastidas</dc:creator>
      <pubDate>Mon, 16 Feb 2026 19:35:24 +0000</pubDate>
      <link>https://forem.com/bastiasa/now-this-is-how-you-create-videogames-192g</link>
      <guid>https://forem.com/bastiasa/now-this-is-how-you-create-videogames-192g</guid>
      <description>&lt;p&gt;I started creating an educational video game about numeric sets with &lt;a href="https://godotengine.org/" rel="noopener noreferrer"&gt;Godot Engine&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8jrahjxeiqz8zlziwvl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8jrahjxeiqz8zlziwvl.webp" alt="Numeric sets video game showcase" width="960" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The idea is this: the more specific the set you place the number in, the more points you get.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding some references
&lt;/h2&gt;

&lt;p&gt;I wanted to show memes when the player placed special numbers such as 67, 69, or 87, which have certain meanings in this cultural context.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;7&lt;/strong&gt;: The most likely number to appear when you roll two dice and sum their results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;67&lt;/strong&gt;: Viral absurd meme.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;87&lt;/strong&gt;: Five Nights at Freddy's lore key date (1987).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Many more&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem? I was doing it manually. It was something like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Convert the video into separate frames.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the frames into the project folder.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Put all the frames inside an animation named after the special number.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optionally put the audio of the meme in another folder and the file must be named after the special number.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So as you can see, this workflow was inefficient, especially because I had to repeat myself a lot and programming is about avoiding these bottlenecks. But even worse, all the animations were inside a single &lt;code&gt;SpriteFrames&lt;/code&gt; resource which severely affects performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Fixing the workflow
&lt;/h3&gt;

&lt;p&gt;Instead of having frames and audio in different folders, I made a special folder in the project where all the subfolders must follow a specific schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/multimedia/special_numbers_animations/
└─ &amp;lt;animation_name&amp;gt;
   ├─ frames (optional folder)
   ├─ audio.ogg (optional)
   ├─ image.{png, jpg} (mandatory if there is no frames folder)
   └─ meta.json - I save the URL sources of the content here.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now instead of having to specify the special number every time, the special number itself determines which animation will play.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const SPECIAL_NUMBERS : Dictionary = {

    308: { # Breaking Bad Reference
        "folder": "waltuh", # This is the &amp;lt;animation_name&amp;gt; folder of the code above.
        "volume_db": 0.0,
        "message": "waltuh" # This is the message which display the green label you can see in the GIFs
    },

    69: {
        "folder":"ts_you",
        "message": "you freak..."
    },

    64: {
        "folder": "homer64",
        "message": "PEAK!",
        "fps":30.0,
        "duration": 187.0 / 30.0
    },

    67: {
        "folder": "six_seven",
        "message": "ABSOLUTE\nSIX-SEVEN! +{score}"
    },

    57: {
        "folder": "peruan_caine",
        "volume_db": -10.0,
        "fps": 6.0,
        "message": "AMAZING! +{score}"
    },

    7: {
        "folder":"miners",
        "message": "gambling, gambling\ngambling, gambling"
    },

    6: {
        "folder":"gta_vi",
        "message": "son...",
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Performance optimization
&lt;/h3&gt;

&lt;p&gt;As we have all the animations in different folders, the code only loads the animations that will be played when the number is placed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if valid_set:

    var _reward = SpecialNumbers.get_reward(number, depth)

    feedback_label.set_color("#00ad00")
    feedback_label.prompt(_reward.text)

    if _reward.is_special:
        special_anims.show_animation(number)

    score += _reward.score
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, loading and releasing animation data every single time can be counterproductive if we want high performance, so I implemented a cache system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func _load(number):
    var _cached = _loaded_animations.get(number)

    if _cached != null:
        return _cached

    # (A lot of code loading the animation like frames, image and audio here).

    var _loaded = LoadedAnimation.new()

    _loaded.image = _image
    _loaded.frames = _frames
    _loaded.audio = _audio
    _loaded.number_info = _special_number_data
    _loaded.audio_player = _audio_player

    _loaded_animations[number] = _loaded
    return _loaded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1li313trhmwau54qeyna.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1li313trhmwau54qeyna.webp" alt="Memes system working" width="960" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we have a scalable and easy memes system!&lt;/p&gt;

&lt;p&gt;This is an important concept to understand. I used to think you just make the game, but it’s not like that at all. At least if you don’t want your code to become &lt;a href="https://www.reddit.com/r/programminghorror/comments/1exqik2/undertale_dialog_system_is_one_giant_switch/" rel="noopener noreferrer"&gt;Undertale&lt;/a&gt;’s cousin. Before creating the game, you must build workflows that optimize creation itself, so you can modify anything in the future with minimal effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  Just remeber
&lt;/h2&gt;

&lt;p&gt;If adding content hurts, your pipeline is wrong.&lt;/p&gt;

</description>
      <category>godotengine</category>
      <category>gamedev</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
