← writing Build journal · 2026-07-19

I shot my passwords across the internet. Pt.2 of the password manager

Last time I wrote about building my own password manager: one encrypted file, one master password, a pixel knight, everything on my laptop. Which left one hole big enough to drive a truck through. My passwords live on the laptop. My logins happen, a lot many times, on my phone, usually while the laptop is in my room and me in my class or maybe I'm a bit too comfortable to move ;p

So this is the mobile chapter: how the vault got to my phone without betraying the whole point of the project, and the two bugs along the way that I thought were pretty interesting.

The ideas I had to kill first

The obvious paths were all wrong for boring reasons. Run the CLI on the phone in a terminal app? Android only, and me and way too many others in this world carry iPhones. Export everything to some established password app's format? Then my tool's mobile story is "use a different tool," which hurts to type. Build an actual iPhone app? I hate myself but I haven't fallen that far yet.

The path that survived: the one app every phone already has. The browser. Safari, Chrome, Firefox — they're all standing there, fully capable, already installed. If my vault could open as a web page, every phone on earth is supported and I ship nothing to any app store.

But a page where? I'm not putting my passwords on a server. That's the exact thing this project exists to not do.

The realization that made it all click

I was thinking for a while before I had moment where i went WAIT! my vault file is already safe to send anywhere. That's not unbased confidence that no one will look, I designed it this way — the file is noise without the master password, which lives in my head and nowhere else. I already tell people to back the vault up to USB sticks and clouds they don't trust. Sending it over the internet is the same move with extra steps.

So the architecture became: my laptop serves a single web page with the encrypted vault baked inside it. My phone opens the page, I type the master password on the phone, and the unscrambling happens right there in the phone's browser. The laptop never sees the password. The network never carries anything but gibberish. The phone stores nothing — close the tab and it's like it never happened.

The lesson that surprised me most. I assumed doing this "properly" over HTTPS would be the annoying compliance part. Backwards. Browsers refuse to give a plain-HTTP page their good tools — the built-in crypto engine, the clipboard — so the insecure version would have needed more code, shipping my own crypto library to do badly what the browser does natively. Going more secure made the whole thing smaller. That one still makes me glad I sat and thought about it for as long as I did and didn't just start writing up the first solution that came to me.

The HTTPS itself comes from a neat free thing: cloudflared's quick tunnels. One command, no account, and your laptop gets a random real-certificate URL that works from any network. My tool runs it for you, prints the URL as a QR code in the terminal, and that's the entire user experience: run paladin mobile, scan with the phone camera, type the one secret word. Done.

And because I already own a domain, there's a mode where the QR always points at my own subdomain instead of a random one — same everything, but bookmarkable. The knight shows up on the phone too, obviously, dressed in whatever theme your terminal was wearing when you made the QR. Details matter.

Into the trenches #1: my phone held the door open

First real test went great — copied passwords on my phone, felt like I made soemthing worthwhile. Then I pressed Ctrl+C to end the session on my laptopand my terminal exploded into a wall of traceback long enough to need make .

The cause is almost sweet. My little web server handled one visitor at a time, and my phone — being a polite, modern browser — keeps its connection open in case it needs anything else. So when I told the server to shut down, it stood there waiting for my phone to finish, forever, like someone holding a door for a person who isn't coming. My second, angrier Ctrl+C landed in the middle of the cleanup code and boom.

Lesson. The bug wasn't in anything I thought was hard. The crypto worked first try. What broke was a door being held open politely. Distributed systems people have known this forever and now I've paid my own tiny tuition: the failure is always in the waiting, not the working.

Into the trenches #2: abstract art

I also put the QR code inside the terminal app itself, themed to your colors, very proud of it. On my screen during development: beautiful. First proper look on a real vault: the QR came out as… vertical slices. A modern art piece. Completely unscannable.

A QR code is a spatial code — every little square's position is data. My layout gave the QR a box slightly too narrow, and the terminal did what terminals do with text that doesn't fit: wrapped it to the next line. Perfectly reasonable for text. Doesn't fit for a QR (pun intended). Every wrapped row moved hundreds of squares to coordinates where they meant nothing.

Lesson. My test checked that the QR rendered. It never checked that it rendered unbroken. Those are different claims, and the gap between them is exactly where bugs live. The fix pins every width to the QR's real size, and the new test measures every rendered line like a suspicious tailor.

The part I didn't build

You can't add or edit passwords from the phone. That's not laziness (okay, it's principled laziness) — the moment two devices can both write, you inherit the entire science of syncing conflicting edits, and I've read enough to know that road eats hobby projects whole. The phone reads, the laptop writes, refresh gets you the fresh vault. If real life ever proves I need phone-side edits, I'll get to that complexity then. As they say, burn that bridge when you get to it or whatever.

One small thing I did add instead of a lock: every time any device loads the page, a line prints in my terminal with the time. I didn't restrict who can open the link — the encryption already answers that question — but now I see every fetch as it happens, and one keypress ends the session. Visibility turned out to be cheaper than restriction and weirdly more reassuring.

Where this leaves things

The tool I wanted at the start of this whole project now actually exists end to end: my passwords live in one unreadable file on my laptop, guarded by one word in my head, and when I need one on my phone I scan a QR, type the word, and tap. The pause while it unlocks is still there — on the phone it's even a touch longer, and I still appreciate why.

The knight travels now. He dresses for the occasion. And every device that knocks on his door gets written down.

Code: github.com/Daisentaur/password-manager ↗ · install: pipx install basic-password-manager · part one: the vault itself
← back to writing