<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Widodo Purnomosidi</title>
    <description>The latest articles on DEV Community by Widodo Purnomosidi (@purnomosidi).</description>
    <link>https://dev.to/purnomosidi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4031469%2F6492a67b-9ff5-4d22-9bdb-f600c386b9ed.jpg</url>
      <title>DEV Community: Widodo Purnomosidi</title>
      <link>https://dev.to/purnomosidi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/purnomosidi"/>
    <language>en</language>
    <item>
      <title>Building CipherBite: An Offline Text Encryption App to Share Credentials Securely</title>
      <dc:creator>Widodo Purnomosidi</dc:creator>
      <pubDate>Fri, 31 Jul 2026 03:37:12 +0000</pubDate>
      <link>https://dev.to/purnomosidi/building-cipherbite-an-offline-text-encryption-app-to-share-credentials-securely-lj4</link>
      <guid>https://dev.to/purnomosidi/building-cipherbite-an-offline-text-encryption-app-to-share-credentials-securely-lj4</guid>
      <description>&lt;p&gt;Sharing sensitive credentials—like passwords, PINs, or API keys—via chat or email is a common habit, but it comes with a massive privacy risk if a device is lost or compromised. As developers, we constantly share environment variables and access tokens over Slack or WhatsApp out of convenience, often ignoring the security implications.&lt;/p&gt;

&lt;p&gt;If you have ever wondered how to send passwords securely on WhatsApp without relying on a bulky password manager, you are not alone. CipherBite is designed to solve this exact problem.&lt;/p&gt;

&lt;p&gt;Instead of sending plain text, CipherBite converts your sensitive information into unique, encrypted cipher text that can only be decoded through the app. I built this offline text encryption app to serve as the perfect middle ground between the convenience of quick messaging and the high-level security of dedicated tools.&lt;/p&gt;

&lt;p&gt;Here is a deep dive into how I built it, the tech stack I chose, and the security architecture behind it.&lt;/p&gt;

&lt;p&gt;🛠️ The Tech Stack&lt;br&gt;
To build a high-performance, natively compiled application from a single codebase, I chose Flutter. For a security-focused app, maintaining a single codebase minimizes the surface area for bugs and vulnerabilities.&lt;/p&gt;

&lt;p&gt;For state management, Riverpod is the backbone of CipherBite. It is compile-safe and seamlessly separates the UI from the heavy AES-256 encryption logic, ensuring the app reacts instantly to database changes—like restoring a vault from a backup—without requiring the user to restart the app.&lt;/p&gt;

&lt;p&gt;🔒 Security First: "Never Roll Your Own Crypto"&lt;br&gt;
When building an app to hide secret text in chat, I had to strictly adhere to the golden rule of cybersecurity: "Never roll your own crypto". Custom encryption algorithms are easily reverse-engineered.&lt;/p&gt;

&lt;p&gt;That is why CipherBite is powered by industry-standard AES-256 encryption, ensuring your data is scrambled into completely secure, unreadable text. Furthermore, the app operates 100% offline, relying entirely on on-device computation without the need for a backend server. This means zero data collection and maximum privacy.&lt;/p&gt;

&lt;p&gt;Users can also encrypt text message with PIN protection, adding an extra layer of security that requires a specific PIN to decode a secret message.&lt;/p&gt;

&lt;p&gt;🗄️ Double-Layer Security with SQLCipher&lt;br&gt;
Local storage is critical for a strictly offline, privacy-first application. To store the user's encryption history locally, I chose SQLite—specifically the SQLCipher implementation.&lt;/p&gt;

&lt;p&gt;This creates a double-layer security architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Text Level: The raw text is scrambled using AES-256.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Storage Level: The .db file saving that AES text is fully encrypted by SQLCipher.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if a device is rooted or compromised, the local vault ensures zero data leaks.&lt;/p&gt;

&lt;p&gt;☁️ Secure Cloud Backups with Google Drive API&lt;br&gt;
While the app is completely offline, users still need a way to back up their local vault. I integrated the Google Drive API to provide a seamless cloud backup solution.&lt;/p&gt;

&lt;p&gt;I chose it specifically because of its unique appDataFolder scope. This scope creates a hidden, protected folder in the user's personal Google Drive. This ensures users have full control over their encrypted backups without the risk of accidentally tampering with or deleting the vault from their regular Drive interface.&lt;/p&gt;

&lt;p&gt;🚀 Wrapping Up&lt;br&gt;
Building CipherBite was an incredible journey in balancing frictionless UX with military-grade security. It acts as a lightweight, privacy-focused alternative to generic encryptors by focusing purely on securing standard messaging apps.&lt;/p&gt;

&lt;p&gt;If you are interested in trying it out, &lt;a href="https://play.google.com/store/apps/details?id=com.purnomosidi.cipherbite" rel="noopener noreferrer"&gt;CipherBite is now available on the Google Play Store&lt;/a&gt;! &lt;/p&gt;

&lt;p&gt;I would love to hear your thoughts, feedback, or any questions about implementing SQLCipher and Google Drive API in Flutter.&lt;/p&gt;

&lt;p&gt;Drop a comment below! 👇&lt;/p&gt;

</description>
      <category>security</category>
      <category>android</category>
      <category>mobile</category>
      <category>flutter</category>
    </item>
    <item>
      <title>Why Your QR Code Can Expire — And How to Make a Permanent One</title>
      <dc:creator>Widodo Purnomosidi</dc:creator>
      <pubDate>Sun, 19 Jul 2026 15:59:37 +0000</pubDate>
      <link>https://dev.to/purnomosidi/why-your-qr-code-can-expire-and-how-to-make-a-permanent-one-4ff3</link>
      <guid>https://dev.to/purnomosidi/why-your-qr-code-can-expire-and-how-to-make-a-permanent-one-4ff3</guid>
      <description>&lt;h1&gt;
  
  
  Why Your QR Code Can Expire — And How to Make a Permanent One
&lt;/h1&gt;

&lt;p&gt;Here's a scenario that's more common than you'd think: you design a beautiful flyer, business card, or product label. You slap a QR code on it, print a few hundred copies, and move on with your life.&lt;/p&gt;

&lt;p&gt;Six months later, someone scans it... and gets a "page not found." Or worse, it redirects to some random ad site that has nothing to do with you.&lt;/p&gt;

&lt;p&gt;You didn't touch the printed material. You didn't change your website. So what happened?&lt;/p&gt;

&lt;p&gt;The QR code itself "expired." And once you understand why, you'll never generate one the same way again.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Sneaky Secret Behind Most "Free" QR Generators
&lt;/h2&gt;

&lt;p&gt;Here's the thing nobody tells you upfront: a huge number of "free" QR code generators don't actually encode &lt;em&gt;your&lt;/em&gt; link into the QR image. Instead, they generate a short redirect URL that lives on &lt;strong&gt;their&lt;/strong&gt; servers — something like &lt;code&gt;qr-provider.io/x7k2p&lt;/code&gt; — and &lt;em&gt;that's&lt;/em&gt; what gets baked into your QR code.&lt;/p&gt;

&lt;p&gt;When someone scans it, their phone hits that provider's server first, which then looks up where you &lt;em&gt;actually&lt;/em&gt; wanted to send people, and redirects them there.&lt;/p&gt;

&lt;p&gt;Why would a "free" tool do this? Mostly for analytics — scan counts, location data, device stats. Sometimes it's a straight-up upsell tactic: track for free, but pay to keep the redirect alive past a trial period.&lt;/p&gt;

&lt;p&gt;It sounds harmless. It isn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Comes Back to Bite You
&lt;/h2&gt;

&lt;p&gt;Once your QR code depends on someone else's redirect server, your printed materials are only as reliable as that company's business decisions. A few ways this goes wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The service shuts down or gets acquired.&lt;/strong&gt; Redirect gone. Every QR code you ever printed with them is now a dead end.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You forget to renew, or hit a free-tier limit.&lt;/strong&gt; Some providers quietly pause dynamic codes until you upgrade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The shortener domain gets repurposed or sold.&lt;/strong&gt; In the worst case, your old QR code could end up pointing somewhere you'd never want it to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You literally cannot fix it after printing.&lt;/strong&gt; Unlike a website, you can't push an update to ink on paper. If the redirect breaks, every flyer, sticker, and business card with that code is trash.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is the real gut-punch. A broken link on a webpage is a five-minute fix. A broken QR code on 5,000 printed labels is a very expensive mistake.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static QR Codes vs. Dynamic QR Codes
&lt;/h2&gt;

&lt;p&gt;A QR code, at its core, is just a clever way to store a chunk of data as a scannable pattern of black-and-white squares. That's it. There's no inherent "expiration" built into the format.&lt;/p&gt;

&lt;p&gt;The difference comes down to &lt;strong&gt;what data actually gets stored&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Static / Direct QR&lt;/th&gt;
&lt;th&gt;Dynamic / Tracking QR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What's encoded&lt;/td&gt;
&lt;td&gt;Your actual content (URL, Wi-Fi password, contact info, etc.)&lt;/td&gt;
&lt;td&gt;A short link pointing to the provider's redirect service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Needs a server to work?&lt;/td&gt;
&lt;td&gt;No — works forever, even offline&lt;/td&gt;
&lt;td&gt;Yes — depends on their infrastructure staying up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can it "expire"?&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes, if the provider stops the redirect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Analytics&lt;/td&gt;
&lt;td&gt;None (by design)&lt;/td&gt;
&lt;td&gt;Usually yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who controls it&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;td&gt;The provider&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Static QR codes are boring in the best possible way — they just work, indefinitely, because there's nothing external to fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Check If Your Current QR Code Is at Risk
&lt;/h2&gt;

&lt;p&gt;Grab your phone and scan any QR code you've already printed. Look at the URL it opens.&lt;/p&gt;

&lt;p&gt;If that URL is on a domain you don't own, and it looks like a shortener (random characters, a generic domain name that isn't yours or your destination's), you're looking at a dynamic code. It's working today, but its lifespan isn't really in your hands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making a QR Code That Actually Lasts
&lt;/h2&gt;

&lt;p&gt;If you're about to print something — packaging, signage, a menu, a conference badge — this is worth doing right the first time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pick a generator that encodes data directly&lt;/strong&gt;, with no middleman redirect. The content should be visible right there in the QR's raw data, not hidden behind a tracking link.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Match the QR type to your actual use case.&lt;/strong&gt; A plain URL works for a website, but formats like vCard (contact info), Wi-Fi credentials, calendar events, or crypto wallet addresses can be encoded directly too — no app or server needed on the other end.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test before you print.&lt;/strong&gt; Scan it with two or three different phones and apps. Don't trust a single preview.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a higher error-correction level&lt;/strong&gt; if the code will be handled, folded, or exposed to wear (think: product packaging vs. a clean digital banner).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the destination itself stable.&lt;/strong&gt; Even with a static code, if you're encoding a URL, make sure that page isn't going anywhere either.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I've been using &lt;a href="https://ic2share.com/qr-generator" rel="noopener noreferrer"&gt;Ic2Share's QR Code Generator&lt;/a&gt; for this exact reason. It runs entirely in your browser (nothing gets uploaded to a server), and it writes your content directly into the QR code — no redirect layer, no expiration, no account needed. It also supports things like vCards, Wi-Fi networks, geolocation, and crypto wallet addresses out of the box, which covers most of the "I need a permanent QR for X" situations you'll run into as a developer or small business owner.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bigger Point
&lt;/h2&gt;

&lt;p&gt;A QR code is supposed to be a bridge — simple, dumb, reliable. The moment you route it through someone else's server for the sake of analytics, you've traded reliability for a dashboard you'll probably check twice and forget about.&lt;/p&gt;

&lt;p&gt;If it's going on anything physical, permanent, or public-facing, encode it directly. Your future self — the one fielding "hey, this code doesn't work" messages — will thank you.&lt;/p&gt;

&lt;p&gt;Have you ever gotten burned by a QR code that stopped working? I'd love to hear the story in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>qr</category>
    </item>
    <item>
      <title>Stop Uploading Images to Random Servers: I Built a 100% Client-Side Image Processor</title>
      <dc:creator>Widodo Purnomosidi</dc:creator>
      <pubDate>Fri, 17 Jul 2026 09:41:22 +0000</pubDate>
      <link>https://dev.to/purnomosidi/stop-uploading-images-to-random-servers-i-built-a-100-client-side-image-processor-5cho</link>
      <guid>https://dev.to/purnomosidi/stop-uploading-images-to-random-servers-i-built-a-100-client-side-image-processor-5cho</guid>
      <description>&lt;p&gt;Have you ever needed to quickly crop, resize, or convert an image, only to find yourself on a random online tool that forces you to upload your sensitive files to their cloud server?&lt;/p&gt;

&lt;p&gt;As a developer, this always bugged me. Not only is it a massive privacy risk (especially when handling personal documents or confidential project assets), but it’s also incredibly inefficient. Why round-trip a 5MB image to a server when modern browsers have all the APIs needed to process it locally?&lt;/p&gt;

&lt;p&gt;That’s why I built the Image Crop, Resize &amp;amp; Convert Tool on Ic2Share.&lt;/p&gt;

&lt;p&gt;It is a 100% client-side, offline-first image processor. Zero server uploads. Zero backend processing. Maximum privacy.&lt;/p&gt;

&lt;p&gt;🏗️ The Architecture: Why Client-Side?&lt;br&gt;
When designing the architecture for my web tools directory, my primary goals were:&lt;/p&gt;

&lt;p&gt;Absolute Privacy: User data should never leave their device.&lt;/p&gt;

&lt;p&gt;Low Operational Cost: By eliminating backend processing, I don't have to pay for expensive compute instances or bandwidth for file uploads/downloads. The entire site can be hosted statically.&lt;/p&gt;

&lt;p&gt;Blazing Speed: Processing happens instantly via the user's own CPU/RAM.&lt;/p&gt;

&lt;p&gt;To achieve this, I ditched traditional backend image libraries like ImageMagick or PHP GD, and relied entirely on Vanilla JavaScript and the HTML5 Canvas API.&lt;/p&gt;

&lt;p&gt;✨ Features of the Tool&lt;br&gt;
Free-form &amp;amp; Aspect Ratio Cropping: Easily crop images for social media headers or profile pictures.&lt;/p&gt;

&lt;p&gt;Scale &amp;amp; Resize: Reduce massive camera photos down to web-friendly dimensions.&lt;/p&gt;

&lt;p&gt;Format Conversion: Convert between JPEG, PNG, and next-gen formats like WebP.&lt;/p&gt;

&lt;p&gt;Quality Compression: Adjust the compression slider to reduce file size without relying on a server-side compression engine.&lt;/p&gt;

&lt;p&gt;🚀 Try It Out&lt;br&gt;
You can test the tool right here: &lt;a href="https://ic2share.com/image-processor" rel="noopener noreferrer"&gt;https://ic2share.com/image-processor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Turn off your Wi-Fi after loading the page, and you'll see that it still works perfectly! This is the power of building offline-first web applications.&lt;/p&gt;

&lt;p&gt;I’d love to hear your thoughts! What other client-side tools do you usually rely on for your daily workflow? Let me know in the comments below! 👇&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>privacy</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I got tired of uploading private files to random servers, so I built a 100% client-side tool suite 🛠️</title>
      <dc:creator>Widodo Purnomosidi</dc:creator>
      <pubDate>Thu, 16 Jul 2026 06:32:21 +0000</pubDate>
      <link>https://dev.to/purnomosidi/i-got-tired-of-uploading-private-files-to-random-servers-so-i-built-a-100-client-side-tool-suite-4dan</link>
      <guid>https://dev.to/purnomosidi/i-got-tired-of-uploading-private-files-to-random-servers-so-i-built-a-100-client-side-tool-suite-4dan</guid>
      <description>&lt;p&gt;Hi DEV community! 👋 I'm Widodo, an independent web and mobile app developer.&lt;/p&gt;

&lt;p&gt;In my day-to-day workflow—whether I am developing mobile apps, structuring databases, or setting up serverless continuous integration pipelines—I constantly rely on quick online utilities. Things like formatting code, generating QR codes, or stripping metadata from images.&lt;/p&gt;

&lt;p&gt;But I realized a massive flaw in the current ecosystem of free online tools: Privacy and Performance.&lt;/p&gt;

&lt;p&gt;If you search for a "Free EXIF Data Remover" or "JSON Formatter," 90% of the top results force you to upload your sensitive files to their remote servers just to perform a basic operation. Not only is this a massive privacy risk, but it also introduces unnecessary latency.&lt;/p&gt;

&lt;p&gt;Since my core development philosophy has always leaned towards offline-first architectures and minimal server dependencies, I decided to build my own solution.&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://ic2share.com" rel="noopener noreferrer"&gt;Ic2Share.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It is a growing directory of web utilities built on a strict zero-server-upload architecture. Everything executes instantly within the user's browser.&lt;/p&gt;

&lt;p&gt;Here is a breakdown of how I built some of the tools and the client-side APIs powering them.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Secure EXIF &amp;amp; Metadata Stripper (Canvas API)
Most EXIF strippers use backend libraries (like PHP's exif_read_data or Python's Pillow). I wanted this to happen entirely offline so users wouldn't have to upload their personal photos.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The solution? HTML5 Canvas Re-rendering.&lt;br&gt;
When a user drops an image, the browser reads it via the FileReader API. I then draw that image onto a hidden  element. When you export the canvas back to a Blob using canvas.toBlob(), the browser automatically discards all original EXIF headers (including the exact GPS coordinates and camera models).&lt;/p&gt;

&lt;p&gt;It is fast, secure, and costs $0 in server compute.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The Online Teleprompter (requestAnimationFrame)&lt;br&gt;
I built an auto-scrolling teleprompter for video creators. Initially, I thought about using CSS transitions or setInterval for the scrolling text. However, CSS can cause jittering on large blocks of text, and setInterval drops frames.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SRT/VTT Subtitle Time Shifter (Regex Engine)&lt;br&gt;
Have you ever downloaded a movie subtitle that is delayed by 2 seconds? I built a tool to fix that. Instead of uploading the .srt file, the user pastes the text, enters the millisecond offset, and Vanilla JS handles the rest using Regular Expressions.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It parses the HH:MM:SS,mmm format, converts it to total milliseconds, applies the shift (forward or backward), calculates the time rollovers, and spits out the synced text instantly.&lt;/p&gt;

&lt;p&gt;The Architecture &amp;amp; Infrastructure&lt;br&gt;
To keep operational costs practically non-existent while ensuring high speed, the entire suite is served statically. I utilize Cloudflare Workers to handle traffic routing and programmatic SEO setups, ensuring the application stays lightweight and highly available globally.&lt;/p&gt;

&lt;p&gt;Other tools currently live on the site include:&lt;/p&gt;

&lt;p&gt;Direct QR Code Generator (Bypasses URL masking)&lt;/p&gt;

&lt;p&gt;Live Markdown Editor (With secure syntax highlighting)&lt;/p&gt;

&lt;p&gt;Invisible Character &amp;amp; Blank Space Generator&lt;/p&gt;

&lt;p&gt;and more..&lt;/p&gt;

&lt;p&gt;I would love your feedback!&lt;br&gt;
Building this has been a fun exercise in maximizing browser capabilities.&lt;/p&gt;

&lt;p&gt;If you have a minute, check out &lt;a href="https://ic2share.com" rel="noopener noreferrer"&gt;https://ic2share.com&lt;/a&gt;.&lt;br&gt;
I would love to hear your thoughts on the UI/UX. Also, as fellow developers, what specific client-side tool do you often wish existed (or was faster) that I can build next?&lt;/p&gt;

&lt;p&gt;Let me know in the comments! 👇&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>privacy</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
