<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Under The Hood]]></title><description><![CDATA[Learn with me about how software and systems work under the hood, by building them from scratch.]]></description><link>https://blogs.abhijeetgautam.in</link><image><url>https://cdn.hashnode.com/uploads/logos/635962286bf8ab0eb983346c/bcf058df-4434-4e76-83ab-e8044b574114.png</url><title>Under The Hood</title><link>https://blogs.abhijeetgautam.in</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 13 May 2026 15:33:02 GMT</lastBuildDate><atom:link href="https://blogs.abhijeetgautam.in/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Metadata vs. I/O: Why Moving Files is (Mostly) a Ledger Update]]></title><description><![CDATA[Most developers assume that moving huge volumes of files is a heavy operation. We’ve all seen the progress bars crawling along as the OS calculates the time remaining, and assumed that the speed is li]]></description><link>https://blogs.abhijeetgautam.in/metadata-vs-i-o-why-moving-files-is-mostly-a-ledger-update</link><guid isPermaLink="true">https://blogs.abhijeetgautam.in/metadata-vs-i-o-why-moving-files-is-mostly-a-ledger-update</guid><category><![CDATA[operating system]]></category><category><![CDATA[cli]]></category><category><![CDATA[file system]]></category><category><![CDATA[devtools]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[software development]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[Performance Optimization]]></category><dc:creator><![CDATA[Abhijeet Gautam]]></dc:creator><pubDate>Sat, 02 May 2026 19:22:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/635962286bf8ab0eb983346c/31956c11-f0a1-4c85-8747-c6e10f00a6a6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most developers assume that moving huge volumes of files is a <em>heavy</em> operation. We’ve all seen the progress bars crawling along as the OS calculates the time remaining, and assumed that the speed is limited by the write speeds of our SSDs.</p>
<p>But <code>forg</code> is a high-performance file-organising CLI tool that challenges this assumption. In our benchmarks, <code>forg</code> moved 20,000 files totalling 22.27 GB in just 2.02 seconds.</p>
<p>That is a <em>"logical throughput"</em> of 11.27 GB/s, far exceeding the physical sequential write speed of almost any consumer drive on the market.</p>
<p>How? The answer lies in understanding that moving a file is rarely about the file itself. Let's understand a little about how <code>forg</code> utilises this concept.</p>
<h2>First of all, what is <code>forg</code>?</h2>
<p><code>forg</code> is a regex-based CLI tool designed to solve the "messy Downloads folder" problem. Written in Rust, it leverages low-level system calls with zero-cost abstractions, ensuring negligible overhead to the OS's native speed.</p>
<p>It uses regex patterns to scan directories and instantly sort files into categorised folders (e.g., .png to Pictures, .mp4 to Videos). Moreover, you can customise all the regex patterns and the destination folders tailored to your workflow.</p>
<p>While the automation is convenient, its speed is what surprises users most.</p>
<h2>How fast does <code>forg</code> perform with different volumes of data?</h2>
<p>Here is how it performs on a standard macOS environment with an APFS (Apple File System):</p>
<table>
<thead>
<tr>
<th>Total files</th>
<th>Total volume</th>
<th>Move time</th>
<th>Logical throughput</th>
</tr>
</thead>
<tbody><tr>
<td>5000</td>
<td>~ 5.4 GB</td>
<td>472 ms</td>
<td>11.7 GB/s</td>
</tr>
<tr>
<td>20000</td>
<td>~ 22.2 GB</td>
<td>2023 ms</td>
<td>11.27 GB/s</td>
</tr>
</tbody></table>
<p>The performance results show that the move time is proportional to the number of files, independent of the volume of the files.</p>
<p><em>Note: See the exact performance testing environment details</em> <a href="https://github.com/Abhijeet-Gautam5702/forg/blob/main/PERFORMANCE_TEST_RESULTS.md"><em>here.</em></a></p>
<h2>The Misconception: Moving v/s Copying</h2>
<p>Most people think of "moving" a file as:</p>
<ol>
<li><p>Copying the data to a new location.</p>
</li>
<li><p>Deleting the data from the old location.</p>
</li>
</ol>
<p>If this were true, moving 20GB would take at least 10–20 seconds on a fast SSD (assuming typical ~2GB/s write speeds). This notion, however, is only partially correct.</p>
<h2>The reality</h2>
<p>To understand why <code>forg</code> is so fast, we have to look at how Operating Systems (like macOS with APFS or Linux with ext4) actually store files.</p>
<p>Internally, a directory is just a special type of file that maps a filename to an <em>inode</em> (the actual address of the data on the disk).</p>
<blockquote>
<p><em>Think of the filesystem like a library. Moving a book from the 'Science' shelf to the 'History' shelf doesn't require rewriting the book. You just update the index in the library's catalog. The book stays exactly where it was on the physical floor; only its 'address' in the system changes.</em></p>
</blockquote>
<h4>So what happens when we 'move' a file?</h4>
<p>Internally, the OS changes the mapping of the <em>inode</em> from the source directory to the destination directory. The file's physical address remains the same, but the mapping is changed.</p>
<p>Similarly, when <code>forg</code> moves a file within the same drive partition, it uses the <em>atomic</em> <code>fs::rename</code> system call (which performs the same logical operation discussed above).</p>
<blockquote>
<p>'Atomic rename' means the operation is all-or-nothing. If the computer loses power midway, the OS ensures the entry is either in the old location or the new one, with no 'in-between' state.</p>
</blockquote>
<p>The actual data on the disk never moves. Not a single bit of the file content is read or written. This is a <strong>metadata-only operation</strong>.</p>
<p>This is why <code>forg</code>'s move time is proportional to the number of files, not the size of the files <em>(as reflected in the performance results section above)</em>. Moving a 1KB text file takes the exact same amount of time as moving a 10GB 4K movie.</p>
<h2>The edge case: Moving to an external drive</h2>
<p>However, the file-moving logic changes completely when you move a file to an external drive or a different partition.</p>
<p>Because the destination drive has its own separate physical disk and filesystem, the OS must physically copy the data across the cable and then delete the original. In this scenario, the file-moving operation becomes I/O-bound. The speed is now strictly limited by the SSD’s write speed or the USB port's bandwidth.</p>
<p>The reason this happens is that an inode has meaning within a single filesystem partition only. Once you cross that boundary (e.g., from your internal SSD to a USB Drive), the bits must physically travel.</p>
<h2>Key takeaways</h2>
<ul>
<li><p>Metadata-bound operation: Moving files <em>within the same drive</em> is just a "label change" in the filesystem’s ledger.</p>
</li>
<li><p>Atomic Renaming: Using <code>fs::rename</code> ensures that if a move fails, the file isn't lost or corrupted.</p>
</li>
<li><p>I/O-bound operation: Moving files to a different drive involves <em>copy-and-delete</em> sequence as the destination now has a separate filesystem of its own.</p>
</li>
<li><p>Logical Throughput: When you see <code>forg</code> hitting 11 GB/s, it’s indicating how fast the OS can update its own mapping records.</p>
</li>
</ul>
<hr />
<h2>Experience the speed yourself</h2>
<p>The next time you’re organising your cluttered folders, don't do it manually. Use <code>forg</code> to get it done in no time.</p>
<p>Checkout the <a href="http://abhijeet-gautam5702.github.io/forg">official documentation</a> for installation steps, or contribute to the performance-first logic on <a href="https://github.com/Abhijeet-Gautam5702/forg">Github</a>.</p>
]]></content:encoded></item><item><title><![CDATA[How to secure your authentication using nonces]]></title><description><![CDATA[Introduction
Nobody wants to get hacked, right?
Just imagine someone walking into your bank and claiming to be you, or worse, someone accessing your personal data by pretending to be your trusted application. When authentication goes wrong, it's not ...]]></description><link>https://blogs.abhijeetgautam.in/how-to-secure-your-authentication-using-nonces</link><guid isPermaLink="true">https://blogs.abhijeetgautam.in/how-to-secure-your-authentication-using-nonces</guid><category><![CDATA[authentication]]></category><category><![CDATA[Security]]></category><category><![CDATA[Nonce]]></category><dc:creator><![CDATA[Abhijeet Gautam]]></dc:creator><pubDate>Tue, 16 Sep 2025 15:18:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1758035791373/f84b4647-71b2-475c-9d1c-08fc79a7e590.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<h3 id="heading-nobody-wants-to-get-hacked-right">Nobody wants to get hacked, right?</h3>
<p>Just imagine someone walking into your bank and claiming to be you, or worse, someone accessing your personal data by pretending to be your trusted application. When authentication goes wrong, it's not just about losing data—it's about losing trust, money, and sometimes even your reputation.</p>
<h3 id="heading-a-single-pass-barcode-to-protect-our-system">A single-pass barcode to protect our system</h3>
<p>What if we had something that could only be used once so the server knows that this request has been made before? Just like a concert ticket with a unique barcode becomes useless once you've used it to enter. This simple idea helps us catch anyone trying to replay old requests to trick our system. This concept is called <strong>nonces</strong> or <em>"Number used once"</em> and we're going to learn exactly that.</p>
<h2 id="heading-understanding-nonces">Understanding Nonces</h2>
<h3 id="heading-what-is-a-nonce">What is a nonce?</h3>
<p>A nonce is a random or pseudo-random number that can only be used once within a cryptographic communication. Nonces are mostly used to preventing replay attacks, where an attacker intercepts a valid request and tries to send it again to gain unauthorised access.</p>
<p>Think of it as giving each request a unique fingerprint that the server can remember and reject if it sees the same fingerprint twice. This way, even if someone captures your login request, they can't simply replay it because the nonce makes each request unique and time-sensitive.</p>
<h3 id="heading-where-do-we-see-nonces">Where do we see Nonces?</h3>
<p>Beyond simple prevention of replay attacks, you might see nonces at different places:</p>
<ul>
<li><p><strong>API Authentication and OAuth2:</strong> Nonces help maintain session integrity and freshness of a request.</p>
</li>
<li><p><strong>Blockchain based transactions:</strong> Nonces prevent double spending attacks.</p>
</li>
<li><p><strong>Password reset tokens &amp; multi-factor authentication:</strong> depend on nonces or <em>nonce-like</em> mechanisms.</p>
</li>
</ul>
<h2 id="heading-building-a-secure-authentication-system">Building a Secure Authentication System</h2>
<h3 id="heading-why-not-go-with-traditional-authentication">Why not go with traditional authentication?</h3>
<p>Traditional authentication systems (and many systems even now) typically work in a straightforward manner where</p>
<ul>
<li><p>Client sends credentials to the server, and</p>
</li>
<li><p>Server responds with a token or session identifier if the credentials are valid.</p>
</li>
</ul>
<p>Traditional systems treat each request independently without any mechanism to detect if the same request has been sent before. This creates a possibility where an attacker can intercept a valid authentication request and replay it multiple times to gain unauthorised access.</p>
<p>Consider a mobile banking app that sends your login credentials over HTTPS. While the transport is encrypted, if an attacker captures the encrypted request, they can replay it later when you're offline to get the credentials from your bank and access your account. The bank server has no way to distinguish between your legitimate login attempt and the attacker's replay because both requests look identical.</p>
<h3 id="heading-introducing-nonces-into-the-authentication-process">Introducing Nonces into the Authentication Process</h3>
<p>To solve the above problem, a nonce gets introduced at the very beginning of the authentication handshake, before any sensitive credentials are exchanged between the client and server. Here's exactly how it works:</p>
<ol>
<li><p>When a client wants to authenticate, it first makes a request to the server asking for a fresh nonce, and the server generates a unique, time-limited number and sends it back to the client.</p>
</li>
<li><p>The client then takes this nonce, combines it with their credentials (often through hashing or signatures), and sends this combined package back to the server for verification.</p>
</li>
<li><p>The server checks both the validity of the credentials and ensures that the nonce hasn't been used before and hasn't expired, effectively creating a two-factor verification system.</p>
</li>
</ol>
<p>This process transforms each authentication attempt into a unique, non-replayable event because even if an attacker captures the entire exchange, the nonce expires and becomes useless for future attempts.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757008226631/ad1d9e07-5116-4221-a1eb-387f31184950.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-implementing-nonces">Implementing Nonces</h2>
<h3 id="heading-generating-nonces-securely">Generating Nonces Securely</h3>
<p>A secure nonce must be <strong>unique and unpredictable</strong>. The most reliable approach involves using a timestamp (uniqueness), combined with random elements (unpredictability). Epoch timestamps work exceptionally well for nonce generation because they naturally provide uniqueness over time—no two requests can have the exact same timestamp down to the millisecond. However, using timestamps alone would make nonces predictable, which is why we need to add a random component to them.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Function to generate a nonce (a pseudo-random set of digits)</span>
<span class="hljs-keyword">const</span> generateNonce = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> currentTimeStamp = <span class="hljs-built_in">Date</span>.now();
    <span class="hljs-keyword">const</span> randomThreeDigits = <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random()*<span class="hljs-number">900</span>) + <span class="hljs-number">100</span>; <span class="hljs-comment">// always ensures a 3-digit number</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${currentTimeStamp}</span><span class="hljs-subst">${randomThreeDigits}</span>`</span>;
};
</code></pre>
<p>This combination creates nonces that are mathematically unique across time and computationally unpredictable, giving your authentication system both reliability and security.</p>
<h2 id="heading-ensuring-communication-security">Ensuring Communication Security</h2>
<h3 id="heading-combine-nonces-with-the-payload-to-create-a-unique-package">Combine nonces with the payload to create a unique package</h3>
<p>The most effective approach is to create a hash (also called a fingerprint) that incorporates both the actual payload and the nonce, making replay attacks impossible even if the hash itself is compromised, as nonces are unique and can be used only once, and so is the hash. Here's how to implement secure credential hashing with nonces:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> crypto = <span class="hljs-built_in">require</span>(<span class="hljs-string">'crypto'</span>);

<span class="hljs-comment">// Utility: creates a hash</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createSecureHash</span>(<span class="hljs-params">password, nonce, salt</span>) </span>{
    <span class="hljs-comment">// Combine password, nonce, and salt for maximum security</span>
    <span class="hljs-keyword">const</span> combined = <span class="hljs-string">`<span class="hljs-subst">${password}</span>:<span class="hljs-subst">${nonce}</span>:<span class="hljs-subst">${salt}</span>`</span>;

    <span class="hljs-comment">// Use SHA-256 for hashing</span>
    <span class="hljs-keyword">const</span> hash = crypto.createHash(<span class="hljs-string">'sha256'</span>)
        .update(combined)
        .digest(<span class="hljs-string">'hex'</span>);

    <span class="hljs-keyword">return</span> hash;
}

<span class="hljs-comment">// Utility: generates a nonce</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateNonce</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> currentTimeStamp = <span class="hljs-built_in">Date</span>.now();
    <span class="hljs-keyword">const</span> randomThreeDigits = <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random()*<span class="hljs-number">900</span>) + <span class="hljs-number">100</span>; <span class="hljs-comment">// always ensures a 3-digit number</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${currentTimeStamp}</span><span class="hljs-subst">${randomThreeDigits}</span>`</span>;
}

<span class="hljs-comment">// Example usage on client side</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">authenticateUser</span>(<span class="hljs-params">username, password</span>) </span>{
    <span class="hljs-keyword">const</span> nonce = generateNonce();
    <span class="hljs-keyword">const</span> salt = <span class="hljs-string">'your-app-specific-salt'</span>; <span class="hljs-comment">// Should be unique per application</span>
    <span class="hljs-keyword">const</span> passwordHash = createSecureHash(password, nonce, salt);

    <span class="hljs-keyword">return</span> {
        username,
        passwordHash,
        nonce
    };
}
</code></pre>
<p>This approach ensures that even if an attacker captures the hash, they can't reuse it because the nonce changes with each request, making the hash completely different every time.</p>
<p><em>In traditional authentication requests, the credentials (username and hashed password) are sent directly to the backend without a nonce. A hacker need not know your password to hack you, but they just need the entire HTTP request (maybe via the cURL or something) to replay the authentication request and mimic you.</em></p>
<p><strong><em>After using nonces, for a hacker to be able to ‘hack’ your account, they need to know your exact password now. Therefore, nonces have reduced a layer of vulnerability by adding another security layer.</em></strong></p>
<h2 id="heading-some-things-to-keep-in-mind">Some things to keep in mind!</h2>
<h3 id="heading-effective-key-management-and-rotation">Effective Key Management and Rotation</h3>
<p>Rotate your nonce generation keys every 30-90 days and never store them in your application code. Set up automated alerts when keys are about to expire so your authentication system doesn't suddenly break in production.</p>
<h3 id="heading-managing-state-with-nonces">Managing State with Nonces</h3>
<p>Store used nonces in a fast database like Redis with automatic expiration to prevent memory bloat, and always check if a nonce has been used before accepting any authentication request.</p>
<h3 id="heading-handling-ux-and-debugging">Handling UX and debugging</h3>
<p>Set nonce expiration times between 5-10 minutes to balance security with user experience. Log nonce generation and validation events <strong><em>(never log the actual nonce values)</em></strong> to help troubleshoot authentication issues in production.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We've journeyed from understanding the fundamental vulnerability of replay attacks to implementing a complete nonce-based authentication system that transforms your application from a sitting duck into a fortress that knows the difference between legitimate users and malicious imposters.</p>
<p>A few extra lines of code and infrastructure setup you invest in nonces today could save you from the nightmare of explaining to users why their data was compromised tomorrow, so make security a priority from day one, not an afterthought when it's too late.</p>
<p>Catch you in the next one.<br />Goodbye!</p>
]]></content:encoded></item><item><title><![CDATA[Starter Guide: Configuring Your Remote Server for Application Deployment]]></title><description><![CDATA[In this article, I will guide you through setting up and securing a remote server, ensuring it is ready for deploying your applications while keeping potential attackers at bay. We will begin by discussing the initial setup of your server and configu...]]></description><link>https://blogs.abhijeetgautam.in/vps-security-starter-guide</link><guid isPermaLink="true">https://blogs.abhijeetgautam.in/vps-security-starter-guide</guid><category><![CDATA[VPS Hosting]]></category><category><![CDATA[server]]></category><category><![CDATA[deployment]]></category><category><![CDATA[linux for beginners]]></category><category><![CDATA[ssh]]></category><category><![CDATA[Security]]></category><dc:creator><![CDATA[Abhijeet Gautam]]></dc:creator><pubDate>Tue, 04 Feb 2025 21:15:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738703192094/465190f2-4942-4236-9ec6-e3953eef0b27.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, I will guide you through setting up and securing a remote server, ensuring it is ready for deploying your applications while keeping potential attackers at bay. We will begin by discussing the initial setup of your server and configuring the necessary software packages. Next, we will delve into securing your server by implementing best practices such as configuring SSH access and disabling root-level access.</p>
<p>By the end of this article, you will have a robust and secure server environment ready for confidently deploying your applications, along with the necessary knowledge of all the key concepts, tools, and terminologies.</p>
<h2 id="heading-why-deploy-apps-online">Why deploy apps online?</h2>
<p>Any app residing on the local machine (i.e., the local host) is inaccessible to others, so we must deploy our applications online for global accessibility. Moreover, a deployed backend application lets developers test it in real conditions and learn production-grade development scenarios.</p>
<h1 id="heading-pre-requisites">Pre-requisites</h1>
<p>Firstly, this tutorial assumes that you are comfortable working with the Linux CLI and have a basic knowledge of Linux commands, like <code>cd</code>, <code>pwd</code>, <code>mv</code>, <code>cp</code>, <code>mkdir</code>, <code>touch</code> etc.</p>
<h2 id="heading-i-linux-based-operating-system">I. Linux-based Operating System</h2>
<p>We will use Ubuntu OS (an operating system built on the Linux kernel) on our local machine and remote host. You don’t need to know the specifics of Ubuntu OS (or Linux) in detail; I will cover everything required in this article.</p>
<blockquote>
<h3 id="heading-windows-subsystem-linux-wsl">Windows Subsystem Linux (WSL)</h3>
<p>Windows Subsystem Linux (WSL) is a compatibility layer developed by Microsoft that allows users to run Linux distributions (simply Linux-based OS, like Ubuntu in our case) on their Windows machines. It provides nearly native Linux experience while letting the developers work from the Windows OS.</p>
<h3 id="heading-installing-ubuntu-on-windows-using-wsl">Installing Ubuntu on Windows using WSL</h3>
<p>Step-1: Open Windows Powershell as administrator and run <code>wsl —install</code> .</p>
<p>Step-2: Open Microsoft Store and install Ubuntu.</p>
<p>Step-3: Open Ubuntu from the Start menu. Create a username &amp; password for the Ubuntu configuration to be used in this Linux environment in future (if needed).</p>
</blockquote>
<p><strong><mark>Note:</mark></strong> In the entire article, the term “terminal“ refers to the Linux terminal, specifically the Ubuntu OS terminal. Although you can theoretically use any terminal of your choice (that supports Linux commands), it is better to stay on the same page for the sake of this article.</p>
<h2 id="heading-ii-virtual-private-server-vps">II. Virtual Private Server (VPS)</h2>
<h3 id="heading-what-is-a-vps">What is a VPS?</h3>
<p>A Virtual Private Server (VPS, also called a remote host or a remote server) is a part of a dedicated server with some resources of its own. In simple terms, a physical server (at a data center) is virtually partitioned into multiple virtual servers (called a VPS instance), each with its own CPU, RAM, and storage. Each VPS instance operates independently of the other VPS instances of the physical server. VPS is a cost-effective alternative to dedicated servers.</p>
<blockquote>
<h3 id="heading-buying-a-vps">Buying a VPS</h3>
<p>Head over to any hosting provider (AWS, Digital Ocean, Hetzner, Hostinger, etc.) and buy any entry-level VPS hosting with low resources to save costs.</p>
<p>In this article, I’ll be using the KVM-1 VPS by Hostinger. Click <a target="_blank" href="https://www.youtube.com/watch?v=ja1Z37QIjo4">here</a> for a short tutorial on how to buy a VPS on Hostinger. The process remains the same for all other providers.</p>
</blockquote>
<h1 id="heading-access-the-vps">Access the VPS</h1>
<p>After purchasing a VPS, you must access it from your local machine. There are different ways to access a VPS, but we will focus on the most common: SSH or Secure Shell.</p>
<h2 id="heading-secure-shell-ssh">Secure Shell (SSH)</h2>
<p>Simply put, SSH is a network protocol (set of rules) that allows two computers to connect securely over an unsecured network. Here are some key features of SSH:</p>
<ol>
<li><p><strong>Secure authentication methods:</strong> via public-private key pairs or password-based logins. <em>(We’ll see them in action later in this article!)</em></p>
</li>
<li><p><strong>Secure file transfers:</strong> it can be used with tools like SCP (Secure Copy Protocol) to securely transfer files from the local machine to the remote host. <em>(Again, we will use SCP later in this article).</em></p>
</li>
</ol>
<h3 id="heading-ssh-into-the-vps-using-the-root-password">SSH into the VPS using the Root Password</h3>
<p>If you buy a VPS from any previously mentioned providers, you will most likely get one with <em>“root login”</em> enabled (except for AWS EC2).</p>
<p><strong><em>What is root login in a VPS?</em></strong></p>
<p>Root login means you will have all the administrative permissions for that VPS and can change the server configurations, files, and services.</p>
<p>Head over to your VPS provider's control panel (or dashboard) and get the following details about your VPS: IP Address, username, and password. For Hostinger’s KVM server, this is where you can find these details.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738327514951/1ee929ac-fabc-4ce3-93b6-34582153556f.png" alt="Hostinger's KVM H-Panel image showing the VPS IP &amp; username" class="image--center mx-auto" /></p>
<ol>
<li><p>Open the terminal (for Windows users, open the Ubuntu from the Start Menu) and run the following command: <code>ssh username@hostIPaddress</code> <em>(Replace</em> <code>username</code> &amp; <code>hostIPaddress</code> with those in your VPS control panel*).*</p>
</li>
<li><p>Enter the root password when asked, and you will be logged into the VPS Linux terminal.</p>
<p> <strong><mark>Note:</mark></strong> While you type the password, it will not be visible on the screen for privacy reasons. You have to type it correctly and responsibly.</p>
</li>
<li><p>After SSH-ing into the VPS (that is, after entering into the VPS), the terminal will look something like this:</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738328092219/f6aa8b03-ad6d-4a82-8f20-9e4d29a40abb.png" alt="VPS terminal showing the server resource usage" class="image--center mx-auto" /></p>
</li>
</ol>
<blockquote>
<p>Don’t get overwhelmed by the terminal screen. It just shows the resources that the VPS is using, its public IP Address, and some links to the Ubuntu documentations - that’s all!</p>
</blockquote>
<p>For now, exit the connection to the VPS by typing <code>exit</code> in the terminal. You will get back to the terminal screen of your local machine.</p>
<p>Let us understand a few other things before working on the VPS again.</p>
<h2 id="heading-ssh-key">SSH Key</h2>
<p>An SSH Key is a cryptographic pair of public and private keys that are used to securely access a server without using the passwords. The public key is stored on the server, and the private key is stored securely on the user's local machine (or the VPS administrator).</p>
<h3 id="heading-why-need-an-ssh-key-when-we-have-password-based-vps-access">Why need an SSH Key when we have password-based VPS access?</h3>
<p>Password-based login poses certain security threats to the server, a few of them are listed below:</p>
<ol>
<li><p>Users tend to choose small passwords that are easy to remember and even easier to guess. Therefore, passwords are more prone to phishing attacks.</p>
</li>
<li><p>Passwords are generally weaker than encrypted keys (SSH Keys, which we’ll see in the next section) and can easily be compromised.</p>
</li>
</ol>
<p>Authentication via an SSH Key has some obvious benefits over password-based authentication:</p>
<ol>
<li><p>You don’t have to remember the password or repeatedly type it whenever you access the remote server.</p>
</li>
<li><p>Unlike passwords (that can be guessed easily), SSH Keys, on the other hand, use strong cryptographic algorithms and are way safer than passwords.</p>
</li>
</ol>
<h3 id="heading-create-an-ssh-key">Create an SSH Key</h3>
<p>Follow the given steps to create an SSH Key pair for your VPS:</p>
<ol>
<li><p>Open the terminal (remember to exit the VPS connection as instructed above) and run the following command:</p>
<pre><code class="lang-bash"> ssh-keygen -t ed25519 -C <span class="hljs-string">"your_email@example.com"</span>
</code></pre>
<p> <em>On a high level, this command generates an SSH key pair using a highly secure</em> <code>Ed25519</code> <em>cryptographic algorithm (</em><code>-t</code> <em>flag). Your email is added as a comment (</em><code>-C</code> <em>flag) for easy distinction in case you have multiple SSH keys in the future (you surely will!)</em></p>
</li>
<li><p>The terminal will prompt you to a default location to save your key pair. Since you are generating a key pair for the first time, simply press enter.</p>
</li>
</ol>
<blockquote>
<p>If you wish, you can change the location or filename but then you will have to remember them all the time. If you created SSH keys previously, <code>ssh-keygen</code> may ask you to rewrite another key, in which case we recommend creating a custom-named SSH key.</p>
<p>In such a case replace the `FILENAME` with your custom file name.</p>
<pre><code class="lang-bash">&gt; Enter a file <span class="hljs-keyword">in</span> <span class="hljs-built_in">which</span> to save the key (/home/YOU/.ssh/id_ALGORITHM): /home/YOU/.ssh/custom_key_name
</code></pre>
</blockquote>
<ol start="3">
<li>Finally, it will prompt you to type a passphrase. You can leave it empty by pressing ENTER.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738440539161/30ceccb7-8b70-49aa-8274-b92202b8bbe4.png" alt="Terminal showing all the commands for creating an SSH Key Pair" class="image--center mx-auto" /></p>
<p>You can see all the SSH keys stored in your machine by navigating to the <code>/home/YOU/.ssh</code> directory and typing <code>ls</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738440991616/93c0b929-4a78-474b-ac68-ecbf6c21bd49.png" alt="Terminal commands to see all the SSH keys stored in local machine" class="image--center mx-auto" /></p>
<p><em>You will see the key pair that was generated just now (default name</em> <code>id_ed25519</code> <em>or your custom name). The key with</em> <code>.pub</code> <em>extension is the public key, which will reside on the VPS to establish a secure connection between the VPS and the local machine.</em></p>
<ol start="4">
<li>Run the following command on the terminal to copy the public SSH key into the VPS.</li>
</ol>
<pre><code class="lang-bash">ssh-copy-id -i <span class="hljs-string">"~/.ssh/id_ed25519.pub"</span> username@hostIPaddress

<span class="hljs-comment"># Remember that the default name for the SSH key will be id_ed25519 unless you change anything while creating the key</span>
<span class="hljs-comment"># Write the appropriate username and IP Address</span>
</code></pre>
<blockquote>
<p>It might be possible that <code>ssh-copy-id</code> is not installed in your system. If that is the case:</p>
<ol>
<li><p>Run <code>sudo apt update &amp;&amp; sudo apt install openssh-client</code> to install openssh-client.</p>
</li>
<li><p>Run <code>command -v ssh-copy-id</code> and confirm if the CLI returns something.</p>
</li>
</ol>
<p>Congrats! <code>ssh-copy-id</code> is now successfully installed and you can now repeat Step-4 above to copy your SSH Key (Public) to the VPS.</p>
</blockquote>
<h3 id="heading-ssh-into-the-vps-using-ssh-key">SSH into the VPS using SSH Key</h3>
<p>Now that we have configured the SSH Key on the local machine and the VPS, we can now access the VPS passwordless:</p>
<pre><code class="lang-bash">ssh -i <span class="hljs-string">"~/.ssh/id_ed25519.pub"</span> username@hostIPaddress

<span class="hljs-comment"># If the filename is kept to default, then the following command will also work</span>
ssh username@hostIPaddress
</code></pre>
<p>Now that we have enabled SSH Key-based login in our VPS, the next step would be to disable password-based login in the VPS.</p>
<h3 id="heading-disable-password-login">Disable Password Login</h3>
<p>We disable password-login in the VPS by changing a few configurations:</p>
<ol>
<li><p>SSH into the server.</p>
</li>
<li><p>Run <code>nano /etc/ssh/sshd_config</code> and the <code>sshd_config</code> file will open in the <strong>nano-editor</strong> (a simple CLI-based editor).</p>
</li>
<li><p>Locate <code>PasswordAuthentication yes</code> and set it to <code>PasswordAuthentication no</code></p>
</li>
<li><p>Press <code>CTRL + X</code>, then <code>Y</code> and then <code>ENTER</code> to save and exit the file.</p>
</li>
<li><p>Run <code>cd /etc/ssh/sshd_config.d/</code> directory and locate a <code>*.conf</code> file (the name could go something like <code>50-cloud-init.conf</code> or similar)</p>
</li>
<li><p>Again locate <code>PasswordAuthentication yes</code> and set it to <code>PasswordAuthentication no</code></p>
</li>
<li><p>Again, press <code>CTRL + X</code>, then <code>Y</code> and then <code>ENTER</code> to save and exit the file.</p>
</li>
<li><p>Run <code>service ssh restart</code> to restart the SSH service so that the changes can apply.</p>
</li>
</ol>
<h2 id="heading-create-a-non-root-user">Create a non-root user</h2>
<h3 id="heading-why-create-a-non-root-user-at-all">Why create a non-root user at all?</h3>
<p>Although most VPS come with root access (except AWS EC2), operating the server with root-level privileges is generally not recommended. Here are a few reasons why:</p>
<ol>
<li><p>Most brute-force hacking attacks on a server occur on the <code>root</code> username.</p>
</li>
<li><p>It is easy to destroy the entire server system if someone gains root access.</p>
</li>
</ol>
<p>A non-root user (also called a <code>sudo</code> group user) provides improved security as the attacker must guess the correct sudo username to enter the system. Moreover, a sudo user has restricted access to the commands in the server.</p>
<blockquote>
<p>A sudo user can perform root-level operations by using the <code>sudo</code> keyword before the command. This is still better than operating as a root user because:</p>
<ol>
<li><p>It can save the server from unintentional damage as it is compulsory to write <code>sudo</code> before every root-level command (therefore, it makes the user think of every action being performed).</p>
</li>
<li><p>Every time a command is prefixed with <code>sudo</code>, it is logged into the server and the specific sudo-user can be tracked down in case of any mistakes.</p>
</li>
</ol>
</blockquote>
<h3 id="heading-steps-to-create-a-non-root-user">Steps to create a non-root user</h3>
<p>Follow the given steps to create a non-root user in your VPS:</p>
<ol>
<li><p>SSH into the VPS as root</p>
<pre><code class="lang-bash"> ssh root@hostIPaddress
</code></pre>
</li>
<li><p>Create a new user</p>
<p> <em>Enter a password of your choice and remember it.</em></p>
<pre><code class="lang-bash"> adduser nonRootUserName
 <span class="hljs-comment"># Replace nonRootUserName with a username of your choice</span>
</code></pre>
</li>
<li><p>Add the non-root user to the <code>sudo</code> group</p>
<pre><code class="lang-bash"> usermod -aG sudo nonRootUserName
</code></pre>
</li>
<li><p>Switch to the new user</p>
<pre><code class="lang-bash"> su - nonRootUserName
</code></pre>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738608907092/94e08d93-2027-4a57-9d10-53bd7c400224.png" alt="Terminal screen showing all the commands to add a new non-root user" class="image--center mx-auto" /></p>
<h3 id="heading-enable-ssh-access-to-the-non-root-user">Enable SSH access to the non-root user</h3>
<p>Follow the given steps to enable SSH access to the non-root user:</p>
<ol>
<li><p>Switch to the new user using <code>su - nonRootUserName</code></p>
</li>
<li><p>Create an SSH directory &amp; change its permissions</p>
<pre><code class="lang-bash"> mkdir -p ~/.ssh
 sudo chmod 700 ~/.ssh   <span class="hljs-comment"># try running this command without the `sudo` keyword</span>
</code></pre>
<blockquote>
<p><code>chmod</code> command changes the permissions of the <code>.ssh</code> directory and <code>700</code> means the owner (i.e., <code>nonRootUserName</code>) has permission to read, write &amp; execute. All other groups and users have no permissions and cannot do anything with the <code>.ssh</code> directory</p>
</blockquote>
</li>
<li><p>Copy the public SSH key from the root <code>.ssh</code> folder</p>
<pre><code class="lang-bash"> sudo cp /root/.ssh/authorized_keys ~/.ssh/
 <span class="hljs-comment"># Run `cat ~/.ssh/authorized_keys` command to see the content inside the copied file</span>
</code></pre>
<blockquote>
<p><code>cp &lt;source_path&gt; &lt;destination_path&gt;</code> command is used to copy files and <code>cat &lt;file_path&gt;</code> command is used to view the contents inside a file.</p>
</blockquote>
</li>
<li><p>Change the permissions of the <code>authorized_keys</code> file &amp; ownership of <code>.ssh</code> directory</p>
<pre><code class="lang-bash"> sudo chmod 600 ~/.ssh/authorized_keys
 sudo chown -R nonRootUserName:nonRootUserName ~/.ssh
</code></pre>
<blockquote>
<ol>
<li><p><code>chmod 600</code> means the owner has permission to read and write only (no execution).</p>
</li>
<li><p><code>chown nonRootUserName:nonRootUserName ~/.ssh</code> means change the ownership of the <code>.ssh</code> folder to <code>nonRootUserName</code> user.</p>
<p> Run <code>ls -la ~/</code> to see the ownership of the <code>.ssh</code> folder</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738611469562/01779fcc-c6d8-4fe8-b769-c6717f8a2fee.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
</blockquote>
</li>
<li><p>Open a new terminal and try accessing the VPS using the non-root username</p>
<pre><code class="lang-bash"> ssh nonRootUserName@hostIPaddress
</code></pre>
</li>
</ol>
<h3 id="heading-disable-root-login">Disable Root Login</h3>
<p>After disabling the root login, you will not be able to SSH into the VPS using <code>ssh root@hostIPaddress</code> anymore. The only way to access the VPS will be through the non-root user.</p>
<p>Follow the given steps to disable root login in your server.</p>
<ol>
<li><p>SSH into the server using root</p>
<pre><code class="lang-bash"> ssh root@hostIPaddress
</code></pre>
</li>
<li><p>Open the <code>sshd_config</code> file &amp; change <code>PermitRootLogin yes</code> to <code>PermitRootLogin no</code></p>
<pre><code class="lang-bash"> nano /etc/ssh/sshd_config
</code></pre>
</li>
<li><p>Save &amp; exit (<code>CTRL+X</code>, then <code>Y</code>, then <code>ENTER</code>)</p>
</li>
<li><p>Restart the SSH service</p>
<pre><code class="lang-bash"> service ssh restart
</code></pre>
</li>
<li><p>Open a new terminal and try accessing the VPS using the root (It will throw an error!)</p>
<pre><code class="lang-bash"> ssh root@hostIPaddress

 <span class="hljs-comment"># The terminal will throw an error</span>
 &gt; Permission denied (publickey)
</code></pre>
</li>
</ol>
<h1 id="heading-set-up-amp-secure-the-server">Set up &amp; secure the server</h1>
<h2 id="heading-update-the-server">Update the server</h2>
<p>Updating and upgrading the OS packages and services must be the first step whenever you log into the VPS system.</p>
<p>You can use <code>apt</code> (Advanced Package Tool) to install dependencies and packages in your VPS.</p>
<blockquote>
<p><code>apt</code> (Advanced Package Tool) is a CLI-based package manager for Linux-based distributions like Ubuntu. It helps users install, update, upgrade, and remove software packages efficiently.</p>
</blockquote>
<pre><code class="lang-bash">sudo apt update &amp;&amp; sudo apt upgrade
</code></pre>
<blockquote>
<h3 id="heading-difference-between-sudo-apt-update-and-sudo-apt-upgrade">Difference between <code>sudo apt update</code> and <code>sudo apt upgrade</code>?</h3>
<p>The VPS system keeps a list of available packages and their versions in an index.</p>
<p><code>sudo apt update</code> looks for all the packages whose newer versions are available and updates the local package index, but does not install them.</p>
<p><code>sudo apt upgrade</code> looks at the local package index and installs the newer versions of the packages already installed in the VPS while keeping the older versions (to avoid breaking any dependency).</p>
</blockquote>
<h2 id="heading-protection-from-brute-force-login-attacks">Protection from brute-force login attacks</h2>
<p>You can set up a service to prevent brute-force login attempts from attackers. <strong>Fail2Ban</strong> is a service that monitors login attempts and bans IPs that fail multiple login attempts in a short span of time.</p>
<p>Follow the given steps to install and configure Fail2Ban:</p>
<ol>
<li><p>Install <code>fail2ban</code></p>
<pre><code class="lang-bash"> sudo apt install fail2ban -y
</code></pre>
</li>
<li><p>Create a local configuration file</p>
<pre><code class="lang-bash"> cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
</code></pre>
</li>
<li><p>Edit the local configuration file</p>
<pre><code class="lang-bash"> sudo nano /etc/fail2ban/jail.local
</code></pre>
<p> Modify the <code>[sshd]</code> section</p>
<pre><code class="lang-bash"> [sshd]
 enabled = <span class="hljs-literal">true</span>
 port = 22
 maxretry = 5
 bantime = 3600
</code></pre>
<blockquote>
<p><code>maxretry = 5</code>: A maximum of 5 failed login attempts will be allowed</p>
<p><code>bantime = 3600</code>: After 5 failed login attempts, the IP will be banned for 3600 seconds (1 hour)</p>
</blockquote>
</li>
<li><p>Restart the service</p>
<pre><code class="lang-bash"> sudo service fail2ban restart
</code></pre>
</li>
</ol>
<blockquote>
<p>You can view the banned IPs by running <code>sudo fail2ban-client status sshd</code> command.</p>
</blockquote>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In this article, we learned how to configure a VPS from scratch properly and set it up to deploy our applications securely. We covered server access, root-level access, SSH keys, creating users, and adding them to groups, along with some best practices for protecting a server from brute-force attacks. Although this article contains much information, it only scratches the surface.</p>
<h2 id="heading-next-steps">Next steps</h2>
<p>Although fairly detailed, this article is not exhaustive. There are many other things a server administrator can do (and should do) to secure a server from phishing and hacking attacks. I would suggest you read about the following topics to strengthen your server administration skills:</p>
<ol>
<li><p><strong>Setting up firewalls and restricting ports:</strong></p>
<p> A firewall acts as a shield and blocks unauthorized access to the VPS by blocking or allowing specific ports only</p>
</li>
<li><p><strong>Restricting the root-level commands for the sudoers:</strong><br /> A sudoer (non-root sudo group user) can technically do all root-level operations using the <code>sudo</code> keyword. So, it becomes critical to restrict and specify the root-level commands for the sudoers.</p>
</li>
<li><p>Setting up 2FA (Two Factor Authentication) for more secure access to the VPS:<br /> Even if an attacker gets hold of your SSH key (by compromising your local machine) and tries to access the VPS, they can not do so if a two-factor authentication is set up in the VPS.</p>
</li>
</ol>
<h2 id="heading-final-thoughts">Final thoughts</h2>
<p>Although they might feel overwhelming for a beginner developer, server configuration and security are necessary and must-have skills for every developer looking to deploy secure and scalable applications online.</p>
<p>I hope this article was able to teach you something.</p>
]]></content:encoded></item><item><title><![CDATA[Dart  [Part-1]: Datatypes and keywords]]></title><description><![CDATA[Introduction
Hello World!
Flutter is an open-source UI software development toolkit created by Google; it is a rapidly growing framework for cross-platform development. Cross-platform development means developing apps for mobile devices, desktops, an...]]></description><link>https://blogs.abhijeetgautam.in/dart-part-1-datatypes-and-keywords</link><guid isPermaLink="true">https://blogs.abhijeetgautam.in/dart-part-1-datatypes-and-keywords</guid><category><![CDATA[Dart]]></category><category><![CDATA[#dart-for-beginners]]></category><category><![CDATA[dart programming tutorial]]></category><category><![CDATA[#dart-keywords]]></category><dc:creator><![CDATA[Abhijeet Gautam]]></dc:creator><pubDate>Sun, 31 Dec 2023 22:05:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1704057715333/16c47cfa-9c7d-425f-8f5d-3d97b1694c8a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Hello World!</p>
<p>Flutter is an open-source UI software development toolkit created by Google; it is a rapidly growing framework for cross-platform development. Cross-platform development means developing apps for mobile devices, desktops, and the web from a single codebase.</p>
<p>Flutter uses the Dart programming language under the hood. In this beginner-friendly blog, we will learn the fundamentals of the Dart programming language. We will be covering a brief history of Dart, and then move directly to data types and keywords provided by Dart.</p>
<h2 id="heading-why-was-dart-created-in-the-first-place">Why was Dart created in the first place?</h2>
<p>Dart was unveiled in 2011. It was designed with a focus on improving web development by addressing limitations in JavaScript. Dart aimed to offer a more structured and efficient alternative for building complex, large-scale web applications compared to JavaScript, which is dynamically typed, lacks certain features and often poses challenges for developers working on ambitious projects (<em>However, JavaScript is still the most widely used language for web development in the world</em>).</p>
<p>Dart shines prominently in frontend development, particularly with the Flutter framework, which utilizes Dart to build natively compiled mobile, web, and desktop applications from a single codebase.</p>
<p>However, Dart is not limited to front-end development. It can also be used for backend development through frameworks like Aqueduct to create RESTful APIs and handle complex backend logic. This allows developers to build full-stack applications using Dart.</p>
<h2 id="heading-what-is-unique-about-dart">What is unique about Dart?</h2>
<p>Let us look at some of Dart's characteristics in the following section.</p>
<h3 id="heading-object-oriented">Object-Oriented</h3>
<p>Dart is an object-oriented programming (OOP) language. But what exactly is an object-oriented programming (OOP) language? Well, it is a programming language that supports the creation of objects- data structures with data fields (simply variables) and methods (also called functions) to build applications.</p>
<p>Dart powers Flutter (which might be why you're learning Dart, right?), and the entire Flutter framework is based on OOP principles like Inheritance, Abstraction, Polymorphism, and Encapsulation.</p>
<p><strong><em><mark>Note:</mark> If you are getting introduced to the above-stated terms for the first time, simply leave it (No Worries!). Just keep in mind that OOP languages allow us to create objects (What are objects? We'll see later). Object-oriented programming is an entirely different topic on its own; we might cover it in a different article.</em></strong></p>
<h3 id="heading-static-type-system">Static type system</h3>
<p>Dart is a statically typed programming language, which means that Dart ensures that the values of variables match their static types (data types defined at the time of writing code). This feature is called <em>type-safety</em> or <em>sound-typing</em>. Type safety is one of the most critical features of Dart.</p>
<p><strong><em><mark>Note:</mark> People from web development backgrounds can think of this feature as the same as TypeScript, as JavaScript is dynamically typed (that means the data type of a variable is not fixed</em></strong>; <strong><em>it can change at any time inside the code without the compiler giving any errors).</em></strong></p>
<h3 id="heading-sound-null-safety">Sound Null Safety</h3>
<p>In Dart, variables can never be <code>null</code> unless the developer says they can be. This can help avoid null exceptions that might occur at runtime. This is how we can declare a null variable.</p>
<pre><code class="lang-dart"><span class="hljs-comment">/* '?' indicates that although the variable 'num' is an integer, but
it can also be null */</span>
<span class="hljs-built_in">int?</span> <span class="hljs-built_in">num</span>;
<span class="hljs-built_in">int</span> nonNullNum; <span class="hljs-comment">// this variable must always be an integer</span>
</code></pre>
<p><strong><em><mark>Note:</mark> JavaScript has no built-in mechanisms to check for null variables. Hence, the developers need to be very careful while dealing with null in JavaScript (this was another reason for the introduction of TypeScript in web development).</em></strong></p>
<p>In the following sections, we will learn about some common data types in Dart, which you might have seen in other programming languages, primarily JavaScript (too many similarities, Huh!)</p>
<h1 id="heading-data-types-in-dart">Data types in Dart</h1>
<p><strong><em><mark>Preliminary Note:</mark> Everything in Dart is an object. You might not know what an object is, and it is completely fine. Objects are not in the scope of this article. Just remember that there is some super-set called an object that encompasses everything else in Dart (even functions).</em></strong></p>
<p>Dart supports many data types similar to other programming languages, such as integers, strings, and booleans. However, Dart also provides unique data types like records, maps, lists, and sets. We will look at all of these in detail.</p>
<p><strong><em><mark>Note: </mark> The syntax to declare any variable (something that stores data) is</em></strong> <code>dataType variableName = variableValue</code></p>
<h2 id="heading-primitive-data-types-in-dart">Primitive data types in Dart</h2>
<p>Below are the primitive datatypes provided by Dart. All of these are self-explanatory; hence, we won't be going into their details (<em>The exciting stuff comes after this!</em>).</p>
<ol>
<li><p><code>int</code> : Store numbers no larger than 64 bits</p>
</li>
<li><p><code>double</code> : Stores 64-bit floating point numbers</p>
</li>
<li><p><code>bool</code> : Stores boolean values (either true or false)</p>
</li>
<li><p><code>String</code> : Stores strings (in double quotes or single quotes)</p>
<pre><code class="lang-dart"> <span class="hljs-built_in">int</span> number = <span class="hljs-number">100</span>; <span class="hljs-comment">// integer</span>
 <span class="hljs-built_in">double</span> weight = <span class="hljs-number">108.10</span>; <span class="hljs-comment">// double</span>
 <span class="hljs-built_in">bool</span> isCitizenOfIndia = <span class="hljs-keyword">true</span>; <span class="hljs-comment">// boolean</span>
 <span class="hljs-comment">// Both are valid strings</span>
 <span class="hljs-built_in">String</span> nameWithDoubleQuotes = <span class="hljs-string">"Abhijeet"</span>;
 <span class="hljs-built_in">String</span> nameWithSingleQuotes = <span class="hljs-string">'Abhijeet'</span>;
</code></pre>
</li>
</ol>
<p><strong><em><mark>Note:</mark> Did you notice that the String datatype starts with a capital letter, whereas other datatypes start with a small letter? That's just how Dart was designed, and we cannot do anything about it. Try to remember it.</em></strong></p>
<h2 id="heading-collections-in-dart">Collections in Dart</h2>
<p>Besides the commonly used data types, Dart also offers collections. "Collections" is a general term that refers to data types (or technically data structures) that store a group of related data together.</p>
<h3 id="heading-lists">Lists</h3>
<p>Just like other programming languages have arrays, Dart has lists, which store data in a sequence.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Syntax: List &lt;another_datatype&gt; listName = [];</span>
<span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">String</span>&gt; listOfCities = [<span class="hljs-string">"New York"</span>, <span class="hljs-string">"New Delhi"</span>, <span class="hljs-string">"Boston"</span>];
<span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">int</span>&gt; listOfMarks = [<span class="hljs-number">23</span>, <span class="hljs-number">45</span>, <span class="hljs-number">90</span>];
<span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">double</span>&gt; listOfHeights = [<span class="hljs-number">100.9</span>, <span class="hljs-number">23.45</span>, <span class="hljs-number">32.109</span>];
</code></pre>
<p>We can create a list of any fundamental/primitive or derived data type. For example, we can have a list of list of strings.</p>
<pre><code class="lang-dart"><span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">String</span>&gt;&gt; names = [
    [<span class="hljs-string">"Abhijeet"</span>],
    [<span class="hljs-string">"Abhishek"</span>, <span class="hljs-string">"Kumar"</span>, <span class="hljs-string">"Gupta"</span>],
    [<span class="hljs-string">"John"</span>, <span class="hljs-string">"Doe"</span>],
];
</code></pre>
<p>We can also create a list consisting of different data types together. Remember, I told you earlier that everything in Dart is an object.</p>
<pre><code class="lang-dart"><span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object</span>&gt; everything = [<span class="hljs-string">"fskhg"</span>,<span class="hljs-keyword">true</span>,<span class="hljs-number">235</span>, <span class="hljs-number">78.0</span>];
</code></pre>
<h3 id="heading-sets">Sets</h3>
<p>Need a data structure that stores unique data only? Dart has got you Sets. A set in Dart is an unordered collection of unique items.</p>
<pre><code class="lang-dart"><span class="hljs-built_in">Set</span>&lt;<span class="hljs-built_in">int</span>&gt; numbers = {<span class="hljs-number">23</span>,<span class="hljs-number">45</span>,<span class="hljs-number">6</span>,<span class="hljs-number">50</span>,<span class="hljs-number">10</span>}; <span class="hljs-comment">// Stores only unique values</span>
<span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">int</span>&gt; numbers2 = [<span class="hljs-number">23</span>, <span class="hljs-number">34</span>, <span class="hljs-number">23</span>, <span class="hljs-number">10</span>]; <span class="hljs-comment">// Can store duplicate values</span>
</code></pre>
<h3 id="heading-maps">Maps</h3>
<p>Maps are collections (or data structures if you wish to call it that) that store data in key-value pairs. Both the keys and values can be of any type.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Syntax: Map&lt;data_type1, data_type2&gt; mapName = {};</span>

<span class="hljs-comment">// A map of Strings and integers</span>
<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">int</span>&gt; studentMarks = {
    <span class="hljs-string">"Smith"</span> : <span class="hljs-number">89</span>,
    <span class="hljs-string">"Abhijeet"</span> : <span class="hljs-number">94</span>,
    <span class="hljs-string">"Alizeh"</span> : <span class="hljs-number">78</span>
};

<span class="hljs-comment">// A map of integers and booleans</span>
<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">int</span>, <span class="hljs-built_in">bool</span>&gt; isEven = {
    <span class="hljs-number">2</span> : <span class="hljs-keyword">true</span>,
    <span class="hljs-number">5</span> : <span class="hljs-keyword">false</span>,
    <span class="hljs-number">11</span> : <span class="hljs-keyword">false</span>
};
</code></pre>
<p><strong><em><mark>Note:</mark> Lists are declared using square brackets (</em></strong><code>[]</code><strong><em>) whereas Maps and Sets are declared using curly braces (</em></strong><code>{}</code><strong><em>).</em></strong></p>
<p><em>Dart provides more data types, such as Runes and Symbols, but they are pretty uncommon and very specific; therefore, they are not covered here. Moreover, there is something called Records in Dart versions beyond 3.0, but they are not covered here to keep this article beginner-friendly.</em></p>
<h1 id="heading-declaring-variables-in-dart">Declaring variables in Dart</h1>
<p>Declaring a variable is pretty straightforward; you have done it a thousand times. Just put a keyword (usually the data type) followed by the variable name.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Syntax to declare a variable =&gt; keyword/data-type variableName;</span>
<span class="hljs-built_in">int</span> number;
<span class="hljs-built_in">String</span> name;
</code></pre>
<p>However, it is not always necessary to define the variable's data type beforehand; sometimes, the developers find it more practical and valuable to have the Dart system (or compiler) <strong><em>infer</em></strong> the data type during the run time. Dart provides specific keywords for this, and we will look into each in the following section.</p>
<h2 id="heading-keywords-in-dart">Keywords in Dart</h2>
<h3 id="heading-var">var</h3>
<p>The <code>var</code> keyword is used when the data stored in the variable can take any potential value. The Dart compiler infers (understands on its own) the data type during compile time (when the code is being compiled). This means that the variable type gets fixed when its value is assigned.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">var</span> anything = <span class="hljs-number">10</span>; <span class="hljs-comment">// Data type of "anything" is integer</span>
anything = <span class="hljs-string">"Abhijeet"</span>; <span class="hljs-comment">// This will give an Error</span>
<span class="hljs-comment">// Data type once inferred by the compiler cannot change now</span>
</code></pre>
<p><strong><em><mark>Note:</mark> People coming from the JavaScript background might get confused here. Let me clear up the confusion.</em></strong><br /><code>var</code> <strong><em>keyword in JavaScript gives dynamic type to the variable, which is checked during the runtime (and not during compile time). So, we can change the type of data stored in the variable without errors.<br />However,</em></strong> <code>var</code> <strong><em>keyword in Dart works a little differently; the data type cannot be changed later if the compiler has inferred it once.</em></strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// IN JAVASCRIPT</span>
<span class="hljs-comment">// variables declared using `var` keyword can change their datatype </span>
<span class="hljs-keyword">var</span> name = <span class="hljs-number">10</span>; <span class="hljs-comment">// datatype is integer</span>
name = <span class="hljs-string">"Abhijeet"</span>; <span class="hljs-comment">// datatype is now string</span>
</code></pre>
<pre><code class="lang-dart"><span class="hljs-comment">// IN DART</span>
<span class="hljs-comment">// variables declared using `var` keyword can't change their datatype</span>
<span class="hljs-keyword">var</span> name = <span class="hljs-number">10</span>; <span class="hljs-comment">// datatype inferred by the compiler as integer</span>
name = <span class="hljs-string">"Abhijeet"</span>; <span class="hljs-comment">// ERROR: A value of type String cannot be </span>
<span class="hljs-comment">// assigned to a variable of type integer</span>
</code></pre>
<h3 id="heading-dynamic">dynamic</h3>
<p>The <code>dynamic</code> keyword stores data with dynamic typing. This means that the type of data being stored in the variable is inferred during the run time (when the dart program is run after being compiled).</p>
<p><em>This is similar to the</em> <code>var</code> <em>keyword of JavaScript.</em></p>
<pre><code class="lang-dart"><span class="hljs-comment">// In Dart, variables declared using `dynamic` keyword can change </span>
<span class="hljs-comment">// their datatypes at any later stage in the code</span>

<span class="hljs-built_in">dynamic</span> name = <span class="hljs-number">10</span>; <span class="hljs-comment">// datatype is integer</span>
name = <span class="hljs-string">"Abhijeet"</span>; <span class="hljs-comment">// datatype is now String</span>
name = [<span class="hljs-string">'new york'</span>, <span class="hljs-string">'boston'</span>]; <span class="hljs-comment">// datatype is now List&lt;String&gt;</span>
name = [<span class="hljs-string">"Abhijeet"</span>, <span class="hljs-number">23</span>]; <span class="hljs-comment">// datatype is now List&lt;dynamic&gt;</span>
</code></pre>
<p><strong><em><mark>Note:</mark> Evidently, the</em></strong> <code>dynamic</code> <strong><em>keyword contradicts Dart's type-safety feature. Therefore, you should avoid using the</em></strong> <code>dynamic</code> <strong><em>keyword wherever possible.</em></strong></p>
<h3 id="heading-the-difference-between-dynamic-and-var">The difference between <code>dynamic</code> and <code>var</code></h3>
<p>The only similarity between <code>var</code> and <code>dynamic</code> is that the values stored in variables declared using both these keywords can be changed at any later stage in the code. Let us talk about the differences between the two.</p>
<p><code>var</code><br />The data type is checked during the compile time.<br />The data type cannot be changed later on.</p>
<p><code>dynamic</code><br />The data type is checked during the run time.<br />The data type can be changed later on.</p>
<h3 id="heading-final">final</h3>
<p>The <code>final</code> keyword can hold any value, but it must not be changed later. The data stored in a <code>final</code> variable cannot be changed (hence the term "constant"). The data type is inferred at the runtime.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">final</span> name = <span class="hljs-string">"Abhijeet"</span>; <span class="hljs-comment">// datatype inferred as String</span>
name = <span class="hljs-string">"Shanaya"</span>; <span class="hljs-comment">// ERROR: A final variable can only be set once</span>
name = <span class="hljs-number">10</span>; <span class="hljs-comment">// ERROR: A value of type integer cannot be assigned</span>
<span class="hljs-comment">// to a variable of type String</span>

<span class="hljs-keyword">final</span> names = [<span class="hljs-string">"Abhi"</span>,<span class="hljs-string">"John"</span>]; <span class="hljs-comment">// datatype inferred List&lt;String&gt;</span>
<span class="hljs-keyword">final</span> list = [<span class="hljs-string">"Abhijeet"</span>, <span class="hljs-keyword">true</span>]; <span class="hljs-comment">// datatype inferred List&lt;Object&gt;</span>
</code></pre>
<p>The more practical use of <code>final</code> variables is to store runtime constants. A runtime constant is a constant value known while the program is running. For instance, some runtime constants are the current date or the response from an external API.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">final</span> date = <span class="hljs-built_in">DateTime</span>.now(); <span class="hljs-comment">// Gives the current date</span>
<span class="hljs-keyword">final</span> response =  <span class="hljs-keyword">await</span> getWeatherData(); <span class="hljs-comment">// Gives current weather</span>
<span class="hljs-comment">// from an external API</span>

<span class="hljs-comment">/* Note: If you do not understand the `await` keyword here, Just 
ignore it. It is used when dealing with asynchronous operations
(more on it in some other article) */</span>
</code></pre>
<h3 id="heading-const">const</h3>
<p>Just like the <code>final</code> keyword, the <code>const</code> keyword is also used to store values that cannot be changed later. The data type is inferred at the compile time (just like <code>var</code>), and hence, any constant that is not a compile-time constant cannot be assigned to a <code>const</code> variable. For instance, API responses and current dates are not compile-time constants.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">const</span> name = <span class="hljs-string">"Abhijeet"</span>; <span class="hljs-comment">// datatype inferred as String</span>
name = <span class="hljs-string">"Shanaya"</span>; <span class="hljs-comment">// ERROR: A const variable can only be set once</span>
name = <span class="hljs-number">10</span>; <span class="hljs-comment">// ERROR: A value of type integer cannot be assigned</span>
<span class="hljs-comment">// to a variable of type String</span>

<span class="hljs-keyword">const</span> list = [<span class="hljs-string">"Abhijeet"</span>, <span class="hljs-keyword">true</span>, <span class="hljs-number">34</span>]; <span class="hljs-comment">// type inferred List&lt;Object&gt;</span>

<span class="hljs-keyword">const</span> date = <span class="hljs-built_in">DateTime</span>.now(); <span class="hljs-comment">// ERROR: Const variables must be </span>
<span class="hljs-comment">// initialized with a constant value</span>
</code></pre>
<h3 id="heading-the-difference-between-final-and-const">The difference between <code>final</code> and <code>const</code></h3>
<p>The following comparison lists some similarities as well as differences between the <code>final</code> and the <code>const</code> keywords.</p>
<p><code>final</code><br />Value, once assigned, cannot be changed.<br />Datatype is inferred at the runtime.<br />It can store runtime constants such as API responses and current dates.</p>
<p><code>const</code><br />Value, once assigned, cannot be changed.<br />Datatype is inferred at the compile-time.<br />It can only store data that is constant at the compile-time.<br />A const variable must be initialized with a value.</p>
<p><strong><em><mark>Note:</mark> Remember that API responses are always handled using the keyword when handling asynchronous operations (Futures in Dart, similar to promises in JavaScript). And use the</em></strong> <code>const</code> <strong><em>keyword to assign constant values to a variable.</em></strong></p>
<p>You can also specify the type while using the <code>final</code> and <code>const</code> keywords to avoid the type inference.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> name = <span class="hljs-string">"Abhijeet"</span>;
<span class="hljs-keyword">const</span> <span class="hljs-built_in">double</span> grade = <span class="hljs-number">7.54</span>;

<span class="hljs-keyword">final</span> <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">int</span>&gt; list = [<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>];
<span class="hljs-keyword">const</span> <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">String</span>&gt; names = [<span class="hljs-string">"Abhijeet"</span>, <span class="hljs-string">"Anshika"</span>];

<span class="hljs-keyword">final</span> <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object</span>&gt; anything = [<span class="hljs-string">"Abhijeet"</span>, <span class="hljs-keyword">true</span>, <span class="hljs-number">45.8</span>, <span class="hljs-number">455</span>];
<span class="hljs-keyword">const</span> <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object</span>&gt; anything2 = [<span class="hljs-string">"Anshika"</span>, <span class="hljs-keyword">false</span>, <span class="hljs-number">95.8</span>, <span class="hljs-number">476</span>];
</code></pre>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In this introductory article, we delved into the basics of Dart programming. We explored Dart's object-oriented nature, its crucial role in powering Flutter, and key features such as static type system and sound null safety. Along with the standard data types, such as Lists, Sets, and Maps, providing a brief overview, the article also elucidated variable declaration using keywords like var, dynamic, final, and const, focusing on clarifying the distinctions between these for beginners.</p>
<p>In conclusion, I hope this article served as a concise foundation for beginners and set the stage for more in-depth exploration in future series installments.</p>
<h1 id="heading-resources-to-learn-more">Resources to Learn more</h1>
<p>You can refer to the following resources to learn more about the Dart programming basics and practice the basic syntax and other concepts.</p>
<ul>
<li><p><a target="_blank" href="https://dart.dev/language">Dart official documentation</a></p>
</li>
<li><p><a target="_blank" href="https://dartpad.dev/">DartPad: To practice writing Dart code without any local setup</a></p>
</li>
</ul>
<p>I will see you at the next one.<br />Till then, Goodbye.</p>
]]></content:encoded></item><item><title><![CDATA[Build an AI Assistant App with Flutter and OpenAI API]]></title><description><![CDATA[Introduction
Are you tired of constantly logging in and out of your chatGPT account? Say no more! In this blog, I'll show you how to create a personal AI assistant mobile application with Flutter and the OpenAI API.
Not only will you be able to add a...]]></description><link>https://blogs.abhijeetgautam.in/build-an-ai-assistant-app-with-flutter-and-openai-api</link><guid isPermaLink="true">https://blogs.abhijeetgautam.in/build-an-ai-assistant-app-with-flutter-and-openai-api</guid><category><![CDATA[Flutter]]></category><category><![CDATA[openai]]></category><category><![CDATA[android app development]]></category><category><![CDATA[APIs]]></category><dc:creator><![CDATA[Abhijeet Gautam]]></dc:creator><pubDate>Wed, 10 May 2023 20:17:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683749569073/bcb0c136-0c9e-46c8-8c90-aa2f3bd729a4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Are you tired of constantly logging in and out of your chatGPT account? Say no more! In this blog, I'll show you how to create a personal AI assistant mobile application with Flutter and the OpenAI API.</p>
<p>Not only will you be able to add an exciting project to your mobile development portfolio, but you'll also be able to flaunt your new AI-assistant application to your friends. So, let's learn how to build an innovative and practical mobile application that will take your development skills to the next level.</p>
<h1 id="heading-getting-the-environment-ready">Getting the environment ready</h1>
<p>Open your terminal and run:</p>
<pre><code class="lang-bash">flutter create &lt;project_name&gt; org com.&lt;your_name&gt;.&lt;project_name&gt;
</code></pre>
<p><strong>NOTE:</strong> <code>&lt;project_name&gt;</code> and <code>&lt;your_name&gt;</code> are placeholders, and you have to write your project name and your own name, respectively (Make sure to remove the <code>&lt; &gt;</code>).</p>
<p>Now, run <code>flutter run</code> to run the project on your device/simulator/web.</p>
<h3 id="heading-adding-custom-fonts-and-assets">Adding custom fonts and assets</h3>
<p>Let us add custom fonts, assets, and env files to our project.</p>
<ol>
<li><p>Create an <code>assets</code> folder in the root directory of the project. The assets folder consists of two other folders - <code>fonts</code> &amp; <code>images</code></p>
</li>
<li><p>Add .otf files of any font of your choice in the <code>fonts</code> folder. Similarly, add any icons or images of your choice in the <code>images</code> folder.</p>
</li>
<li><p>Open the <code>pubspec.yaml</code> file and copy the following code under the <code>flutter</code> package section.</p>
</li>
</ol>
<pre><code class="lang-yaml"><span class="hljs-attr">flutter:</span>
  <span class="hljs-attr">uses-material-design:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">assets:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">assets/images/</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">.env</span>
  <span class="hljs-attr">fonts:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">family:</span> <span class="hljs-string">Cera</span> <span class="hljs-string">Pro</span>
      <span class="hljs-attr">fonts:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">asset:</span> <span class="hljs-string">assets/fonts/Cera-Pro-Bold.otf</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">asset:</span> <span class="hljs-string">assets/fonts/Cera-Pro-Medium.otf</span>
</code></pre>
<p><strong>NOTE-1:</strong> You must take care of the indentation.</p>
<p><strong>NOTE-2:</strong> Every time you make any changes to <code>pubspec.yaml</code> file, always run <code>flutter pub get</code> command.</p>
<h3 id="heading-creating-the-color-palette">Creating the Color Palette</h3>
<p>Let's create a file inside the <code>lib</code> folder containing all the colors we'll use throughout the project. A benefit of creating a separate file for such purposes is that we'll have to do it only once whenever we change the colors in the future.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Pallete</span> </span>{
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> Color borderColor = Color.fromRGBO(<span class="hljs-number">200</span>, <span class="hljs-number">200</span>, <span class="hljs-number">200</span>, <span class="hljs-number">1</span>);
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> Color whiteColor = Colors.white;
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> Color textFieldColor = Color.fromRGBO(<span class="hljs-number">52</span>, <span class="hljs-number">53</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>);
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> Color textBoxColor = Color.fromRGBO(<span class="hljs-number">65</span>, <span class="hljs-number">65</span>, <span class="hljs-number">78</span>, <span class="hljs-number">1</span>);
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> Color primaryColor = Color.fromRGBO(<span class="hljs-number">24</span>, <span class="hljs-number">201</span>, <span class="hljs-number">245</span>, <span class="hljs-number">1</span>);
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> Color chatColor = Color.fromRGBO(<span class="hljs-number">68</span>, <span class="hljs-number">70</span>, <span class="hljs-number">84</span>, <span class="hljs-number">1</span>);
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> Color appBarColor = Color.fromRGBO(<span class="hljs-number">32</span>, <span class="hljs-number">33</span>, <span class="hljs-number">35</span>, <span class="hljs-number">1</span>);
}
</code></pre>
<h1 id="heading-lets-start">Let's start</h1>
<p>Now that we have installed all the necessary dependencies and packages, let us start with the real stuff - coding our app. I will be explaining the code and its logic. However, I assume that the implementation of basic UI using Flutter is known to you, so I will skip explaining those portions.</p>
<p>We will work inside the <code>lib</code> folder throughout our project.</p>
<h2 id="heading-maindart">main.dart</h2>
<p>Pretty customary section! This file contains the <code>MyApp</code> widget.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter_dotenv/flutter_dotenv.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:jarvis/homepage.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:jarvis/pallete.dart'</span>;

<span class="hljs-comment">// the main function is made async. This enables us to use await keyword with dotenv inside.</span>
Future&lt;<span class="hljs-keyword">void</span>&gt; main() <span class="hljs-keyword">async</span> {
  <span class="hljs-keyword">await</span> dotenv.load(); <span class="hljs-comment">// loads all the environment variables</span>
  runApp(<span class="hljs-keyword">const</span> MyApp());
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> MyApp({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-comment">// This widget is the root of your application.</span>
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      debugShowCheckedModeBanner: <span class="hljs-keyword">false</span>,
      title: <span class="hljs-string">'Jarvis'</span>,
      theme: ThemeData.light(useMaterial3: <span class="hljs-keyword">true</span>).copyWith(
        scaffoldBackgroundColor: Pallete.whiteColor,
        appBarTheme: <span class="hljs-keyword">const</span> AppBarTheme(
          backgroundColor: Pallete.whiteColor,
        ),
      ),
      home: <span class="hljs-keyword">const</span> HomePage(),
    );
  }
}
</code></pre>
<h2 id="heading-homepage-widget">Homepage widget</h2>
<p>We will use the Homepage widget to set up the app bar only. The rest of the sections will be dealt with later.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:jarvis/chat_section.dart'</span>; <span class="hljs-comment">// ChatSection</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:jarvis/pallete.dart'</span>; <span class="hljs-comment">// Color Pallete</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HomePage</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  <span class="hljs-keyword">const</span> HomePage({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-meta">@override</span>
  State&lt;HomePage&gt; createState() =&gt; _HomePageState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_HomePageState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">HomePage</span>&gt; </span>{

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(
        backgroundColor: Pallete.appBarColor,
        elevation: <span class="hljs-number">2</span>,
        title: <span class="hljs-keyword">const</span> Text(
          <span class="hljs-string">'J  A  R  V  I  S'</span>,
          style: TextStyle(
            fontSize: <span class="hljs-number">18</span>,
            color: Colors.white,
            fontWeight: FontWeight.w500,
            fontFamily: <span class="hljs-string">"Cera Pro"</span>, <span class="hljs-comment">//make sure to add custom fonts to pubspec.yaml</span>
          ),
        ),
        centerTitle: <span class="hljs-keyword">true</span>,
      ),
      body: Container(
        decoration: <span class="hljs-keyword">const</span> BoxDecoration(
          color: Pallete.chatColor,
        ),
        child: <span class="hljs-keyword">const</span> ChatSection(), <span class="hljs-comment">// widget explained below</span>
      ),
    );
  }
}
</code></pre>
<h2 id="heading-chatsection-widget">ChatSection widget</h2>
<p>The chat section will contain the entire UI of our app. The code will be pretty simple (as the most exciting part comes after this).</p>
<p><strong>NOTE:</strong> The ChatSection widget will be stateful.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>; <span class="hljs-comment">// material package</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:jarvis/open_ai_service.dart'</span>; <span class="hljs-comment">// OpenAiService class</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:jarvis/pallete.dart'</span>; <span class="hljs-comment">// Pallet containing colors</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ChatSection</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  <span class="hljs-keyword">const</span> ChatSection({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-meta">@override</span>
  State&lt;ChatSection&gt; createState() =&gt; _ChatSectionState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_ChatSectionState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">ChatSection</span>&gt; </span>{
  <span class="hljs-comment">// to control the text input field (i.e. access the value input by user)</span>
  TextEditingController promptController = TextEditingController();

  <span class="hljs-built_in">String</span> prompt = <span class="hljs-string">''</span>; <span class="hljs-comment">// stores the user prompt</span>
  <span class="hljs-built_in">String</span> chatSpeech = <span class="hljs-string">''</span>; <span class="hljs-comment">// stores the response from the API</span>

  <span class="hljs-built_in">bool</span> showLoader = <span class="hljs-keyword">false</span>; <span class="hljs-comment">// whether to show loader or not</span>

  <span class="hljs-comment">// define class openAiService (type of class = OpenAiService) </span>
  <span class="hljs-keyword">final</span> OpenAiService openAiService = OpenAiService();

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> dispose() {
    promptController.dispose();
    <span class="hljs-keyword">super</span>.dispose();
  }

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Column(
        children: [
            <span class="hljs-comment">// chatGPT Response Container (explained below)</span>
            <span class="hljs-comment">// Prompt Input Section (explained below)</span>
        ]
    );
  }
}
</code></pre>
<p>We will have the following two sections in the ChatSection widget.</p>
<ol>
<li><p>ChatGPT Response Section</p>
</li>
<li><p>Prompt Input Section</p>
</li>
</ol>
<h3 id="heading-prompt-input-section">Prompt Input Section</h3>
<p>Let's start with the interesting one, the Prompt Input Section. Most of the code will be for the UI, so there is not much to explain there; hence, look at the code directly.</p>
<pre><code class="lang-dart">        <span class="hljs-comment">// Prompt Input section</span>
        Container(
          height: MediaQuery.of(context).size.height * <span class="hljs-number">0.12</span>,
          decoration: <span class="hljs-keyword">const</span> BoxDecoration(
            color: Pallete.textFieldColor,
            borderRadius: BorderRadius.only(
              topLeft: Radius.circular(
                <span class="hljs-number">0</span>,
              ),
              topRight: Radius.circular(
                <span class="hljs-number">0</span>,
              ),
            ),
          ),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisSize: MainAxisSize.max,
            children: [
              <span class="hljs-comment">//Input text field</span>
              Expanded(
                child: Container(
                  <span class="hljs-comment">// width: MediaQuery.of(context).size.width * 0.8,</span>
                  padding: <span class="hljs-keyword">const</span> EdgeInsets.all(<span class="hljs-number">8</span>),
                  child: TextField(
                    cursorColor: Colors.grey,
                    cursorHeight: <span class="hljs-number">30</span>,
                    controller: promptController,
                    autocorrect: <span class="hljs-keyword">true</span>,
                    autofocus: <span class="hljs-keyword">true</span>,
                    <span class="hljs-comment">// maxLength: 200,</span>
                    maxLines: <span class="hljs-keyword">null</span>,
                    keyboardType: TextInputType.multiline,
                    style: <span class="hljs-keyword">const</span> TextStyle(
                      color: Colors.white,
                      fontFamily: <span class="hljs-string">"Cera Pro"</span>,<span class="hljs-comment">// make sure to add custom fonts to pubspec.yaml</span>
                    ),
                    decoration: InputDecoration(
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(<span class="hljs-number">7</span>),
                        borderSide: BorderSide.none,
                      ),
                      filled: <span class="hljs-keyword">true</span>,
                      fillColor: Pallete.textBoxColor,
                      hintStyle: <span class="hljs-keyword">const</span> TextStyle(
                        color: Colors.grey,
                      ),
                      hintText: <span class="hljs-string">'Give me a prompt...'</span>,
                    ),
                  ),
                ),
              ),

              <span class="hljs-comment">// Send Button</span>
              IconButton(
                onPressed: ()=&gt;{}, <span class="hljs-comment">// code explained below</span>
                icon: <span class="hljs-keyword">const</span> Icon(
                  Icons.send,
                  color: Pallete.primaryColor,
                  size: <span class="hljs-number">26</span>,
                ),
              ),
            ],
          ),
        )
</code></pre>
<p>Let's focus our attention on the <code>onPressed</code> property of the <code>IconButton</code> widget.</p>
<p>When the Send button is pressed, a function is called to post the prompt to the OpenAI API and fetch the response. A loader will be displayed on the response container until the API returns the response. So, the following events take place when send button is pressed.</p>
<ol>
<li><p>The value of the input text field is stored in the <code>prompt</code> variable. The state of <code>prompt</code> is modified.</p>
</li>
<li><p>The <code>prompt</code> is passed as an argument to the chatGPTApi method of the <code>openAiService</code> class. The <code>chatGPTApi()</code> method is an async function (returning a Future), so the result is awaited using the <code>await</code> keyword.</p>
</li>
<li><p>The API response is stored in a <code>speech</code> variable.</p>
</li>
</ol>
<pre><code class="lang-dart"><span class="hljs-comment">// Write this block of code in the 'onPressed' field of IconButton widget.</span>

onPressed: () <span class="hljs-keyword">async</span> {
                  setState(
                    () {
                      prompt = promptController.value.text.toString();
                      showLoader = <span class="hljs-keyword">true</span>;
                    },
                  );
                  <span class="hljs-keyword">final</span> speech = <span class="hljs-keyword">await</span> openAiService.chatGPTApi(prompt);
                  setState(() {
                    chatSpeech = speech;
                    showLoader = <span class="hljs-keyword">false</span>;
                  });
                  <span class="hljs-comment">// print(speech);</span>
                  promptController.clear();
                },
</code></pre>
<h3 id="heading-chatgpt-response-section">ChatGPT Response Section</h3>
<p>This section will be the just UI. Besides, some things to note.</p>
<ol>
<li><p>This section will be wrapped inside the <code>Expanded</code> widget, as we want this section to take up all the space available.</p>
</li>
<li><p>This section needs to be scrollable, so wrap it in <code>SingleChildScrollView</code> widget.</p>
</li>
<li><p>If the <code>isShowLoader</code> is true, then show a loader. Otherwise, check for the value of the <code>speech</code> variable; if empty, display some introductory message. Else, display the response returned by the API.</p>
</li>
</ol>
<p>The following is the code for this section (Don't worry if it seems long!! It's just FLUTTER UI).</p>
<pre><code class="lang-dart"><span class="hljs-comment">// chatGPT response container</span>
Expanded(
  child: SingleChildScrollView(
    child: Align(
      alignment: Alignment.topLeft,
      <span class="hljs-comment">//chatGPT response chat bubble</span>
      child: showLoader == <span class="hljs-keyword">true</span>
          ? <span class="hljs-keyword">const</span> Center(
              child: Padding(
                padding: EdgeInsets.only(
                  top: <span class="hljs-number">30.0</span>,
                ),
                child: CircularProgressIndicator(
                  color: Pallete.primaryColor,
                ),
              ),
            )
          <span class="hljs-comment">// Main content</span>
          : Row(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.max,
              children: [
                <span class="hljs-comment">// small icon of a robot/assistant </span>
                Padding(
                  padding: <span class="hljs-keyword">const</span> EdgeInsets.only(
                    top: <span class="hljs-number">15.0</span>,
                  ),
                  child: Image.asset(
                    <span class="hljs-string">"path_to_any_icon_of_your_choice"</span>,
                    width: <span class="hljs-number">40</span>,
                  ),
                ),
                <span class="hljs-comment">// Response Box</span>
                Expanded(
                  child: Container(
                    margin: <span class="hljs-keyword">const</span> EdgeInsets.symmetric(
                      horizontal: <span class="hljs-number">10</span>,
                      vertical: <span class="hljs-number">20</span>,
                    ),
                    padding: <span class="hljs-keyword">const</span> EdgeInsets.all(<span class="hljs-number">10</span>),
                    decoration: BoxDecoration(
                      border: Border.all(
                        color: Pallete.borderColor,
                      ),
                      borderRadius: BorderRadius.circular(<span class="hljs-number">10</span>),
                    ),
                    child: Text(
                      chatSpeech == <span class="hljs-string">""</span>
                          ? <span class="hljs-string">"HEY ! How may I help you?"</span>
                          : chatSpeech,
                      style: <span class="hljs-keyword">const</span> TextStyle(
                        color: Pallete.borderColor,
                        fontFamily: <span class="hljs-string">"Cera Pro"</span>,
                      ),
                    ),
                  ),
                ),
              ],
            ),
    ),
  ),
),
</code></pre>
<h2 id="heading-creating-openaiservice">Creating OpenAiService</h2>
<p>Let's work on the open_ai_service.dart file, which is the most critical file in our project. This file would contain methods to post queries and receive responses from the OpenAI API.</p>
<p>Firstly, install all the packages and modules required for further coding. We'll need the <code>http</code> package (to interact with OpenAI API) and the <code>dot_env</code> package (to access the environment variables). Navigate to your project directory and run the following commands on your terminal.</p>
<pre><code class="lang-bash">flutter pub add http
flutter pub add dot_env
flutter pub get
</code></pre>
<h3 id="heading-env">.env</h3>
<p>Environment variables are the ones that store sensitive data (something which must not be publicly visible). Here, we will store our private API key as an environment variable. Create a <code>.env</code> file in the root directory of your Flutter project and define the API key as an environment variable.</p>
<pre><code class="lang-dart">OPEN_AI_API_KEY = <span class="hljs-string">"paste your API key here"</span>
</code></pre>
<p><strong>NOTE:</strong> Make sure that you include the <code>.env</code> file in <code>.gitignore</code> before pushing your code to GitHub (or a similar platform).</p>
<h3 id="heading-the-requestresponse-structure-of-openai-api">The request/response structure of OpenAI API</h3>
<p>Firstly, sign up for an OpenAI account and <a target="_blank" href="https://www.howtogeek.com/885918/how-to-get-an-openai-api-key/">generate a free API key</a>.</p>
<p>Head over to the API <a target="_blank" href="https://platform.openai.com/docs/api-reference/chat/create?lang=curl">reference section of the OpenAI website</a> and look for the Chat section. This model generates responses based on a conversation (i.e., it remembers the chats).</p>
<p>You can see the example request and response shown in the documentation. The structure of the <strong>HTTP-post request</strong> will look like this.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// structure of the API request (in dart code)</span>
http.post(
    <span class="hljs-built_in">Uri</span>.parse(<span class="hljs-string">"https://api.openai.com/v1/chat/completions"</span>),
    headers:{
        <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
        <span class="hljs-string">"Authorization"</span>: <span class="hljs-string">"Bearer <span class="hljs-subst">$openAIApiKey</span>"</span>
    },
    <span class="hljs-comment">// the body needs to be converted to JSON format</span>
    body: jsonEncode(
        {
            <span class="hljs-string">"model"</span> : <span class="hljs-string">"gpt-3.5-turbo"</span>,
            <span class="hljs-string">"messages"</span> : messages,
        },
    ),
);
</code></pre>
<p>The response from the API will look something like this.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// structure of API response body (in json format)</span>
{
  <span class="hljs-string">"id"</span>: <span class="hljs-string">"chatcmpl-123"</span>,
  <span class="hljs-string">"object"</span>: <span class="hljs-string">"chat.completion"</span>,
  <span class="hljs-string">"created"</span>: <span class="hljs-number">1677652288</span>,
  <span class="hljs-string">"choices"</span>: [{
    <span class="hljs-string">"index"</span>: <span class="hljs-number">0</span>,
    <span class="hljs-string">"message"</span>: {
      <span class="hljs-string">"role"</span>: <span class="hljs-string">"assistant"</span>,
      <span class="hljs-string">"content"</span>: <span class="hljs-string">"\n\nHello there, how may I assist you today?"</span>,
    },
    <span class="hljs-string">"finish_reason"</span>: <span class="hljs-string">"stop"</span>
  }],
  <span class="hljs-string">"usage"</span>: {
    <span class="hljs-string">"prompt_tokens"</span>: <span class="hljs-number">9</span>,
    <span class="hljs-string">"completion_tokens"</span>: <span class="hljs-number">12</span>,
    <span class="hljs-string">"total_tokens"</span>: <span class="hljs-number">21</span>
  }
}
</code></pre>
<p>Do not worry; we are interested only in the <code>message</code> field (under the choices <code>property</code>). Since the API response will be returned in JSON format, we must parse/decode it before using it.</p>
<h3 id="heading-creating-the-openaiservice-class">Creating the OpenAiService class</h3>
<p>Now we'll create the OpenAiService class and define the methods for posting requests to the OpenAI API.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'dart:convert'</span>; <span class="hljs-comment">// package to encode/decode JSON data type</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter_dotenv/flutter_dotenv.dart'</span>; <span class="hljs-comment">// dot_env package</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:http/http.dart'</span> <span class="hljs-keyword">as</span> http; <span class="hljs-comment">// http package</span>

<span class="hljs-keyword">var</span> openAIApiKey = dotenv.env[<span class="hljs-string">'OPEN_AI_API_KEY'</span>]; <span class="hljs-comment">//access the OPEN_AI_API_KEY from the .env file in the root directory</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OpenAiService</span></span>{
    <span class="hljs-comment">// declaring a messages List to maintain chat history</span>
    <span class="hljs-keyword">final</span> <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>,<span class="hljs-built_in">String</span>&gt;&gt; messages = [
        {
            <span class="hljs-string">"role"</span> : <span class="hljs-string">"user"</span>,
            <span class="hljs-string">"content"</span> : <span class="hljs-string">"Ensure all responses within 200         words"</span>,
        },
    ];

    <span class="hljs-comment">// this async function with return a future which will resolve to a string</span>
    Future&lt;<span class="hljs-built_in">String</span>&gt; chatGPTApi(<span class="hljs-built_in">String</span> prompt) <span class="hljs-keyword">async</span>{
        <span class="hljs-comment">// add the prompt to messages</span>
        messages.add({
            <span class="hljs-string">"role"</span> : <span class="hljs-string">"user"</span>,
            <span class="hljs-string">"content"</span> : prompt,
        });

        <span class="hljs-comment">// post the prompt to the API and receive response</span>
        <span class="hljs-keyword">try</span>{
            <span class="hljs-keyword">final</span> res = http.post(
                <span class="hljs-built_in">Uri</span>.parse(<span class="hljs-string">"https://api.openai.com/v1/chat/completions"</span>),
                headers:{
                    <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
                    <span class="hljs-string">"Authorization"</span>: <span class="hljs-string">"Bearer <span class="hljs-subst">$openAIApiKey</span>"</span>
                },
                <span class="hljs-comment">// encode the object to JSON</span>
                body: jsonEncode(
                    {
                        <span class="hljs-string">"model"</span> : <span class="hljs-string">"gpt-3.5-turbo"</span>,
                        <span class="hljs-string">"messages"</span> : messages,
                    },
                ),
            );

            <span class="hljs-keyword">if</span>(res.statusCode == <span class="hljs-number">200</span>){
                <span class="hljs-comment">// decode the JSON response</span>
                <span class="hljs-built_in">String</span> response = jsonDecode(res.body)[<span class="hljs-string">'choices'</span>][<span class="hljs-number">0</span>][<span class="hljs-string">'message'</span>][<span class="hljs-string">'content'</span>];
                response = response.trim();
                <span class="hljs-comment">// add the response to messages and return response</span>
                messages.add(
                    {
                        <span class="hljs-string">"role"</span> : <span class="hljs-string">"assistant"</span>,
                        <span class="hljs-string">"content"</span> : response,
                    }
                );
                <span class="hljs-keyword">return</span> response;        
            }
            <span class="hljs-keyword">else</span>{
                <span class="hljs-keyword">return</span> <span class="hljs-string">"OOPS! An Error occured. \n Please try again after sometime"</span>;
            }
        }
        <span class="hljs-keyword">catch</span> (error){
            <span class="hljs-keyword">return</span> error.toString();
        }
    }
}
</code></pre>
<h1 id="heading-generating-an-apk-file">Generating an apk file</h1>
<p>To test the application on an Android device, we need to install the apk-file of our project. Open the terminal and run:</p>
<pre><code class="lang-bash">flutter build apk --release
</code></pre>
<p>The terminal will show you the exact path of the apk file. Transfer it to your mobile and test it.</p>
<p><strong>NOTE:</strong> You might have to allow installation from unknown sources in your device settings to install the apk.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In this tutorial, we created a working mobile application using the OpenAI API to answer all our queries. We learned about making HTTP requests and using environment variables to store sensitive information like API keys. Also, we modularized our code by creating separate widgets.</p>
<p>I hope you enjoyed this tutorial &amp; I was able to add value to your development journey through this blog. You can find the source code of this project <a target="_blank" href="https://github.com/Abhijeet-Gautam5702/Jarvis">here</a>.</p>
<p>Do like and share this blog, and follow me for more such content.</p>
<p>See you at the next one !!</p>
]]></content:encoded></item></channel></rss>