2026 July 10
I wanted to send files between my laptop and phone without opening a cloud drive, plugging in a cable, or installing an app on the phone. The obvious answer is a small HTTP server: run it in a folder, print a QR code, let the phone's browser do the rest. That's wifiler. The interesting part wasn't the file serving - that's a net/http handler and a directory listing - it was deciding, deliberately, what kind of tool this should and shouldn't try to be.
The first version used net.InterfaceAddrs() and returned the first non-loopback IPv4 address it found. That's fine until your machine has more than one network interface, which on any modern laptop is basically always - Docker, WSL, a VPN client, or (the one that actually bit me) Windows Mobile Hotspot, which hands out addresses in 192.168.137.x by default. If that adapter enumerates first, wifiler prints a perfectly valid, completely unreachable address, and the phone just times out with no clear reason why.
The fix was to stop enumerating interfaces and instead ask the OS which address it would actually use to route outbound traffic:
conn, err := net.Dial("udp", "8.8.8.8:80")
...
localAddr := conn.LocalAddr().(*net.UDPAddr)
No packets are sent - UDP dial is just a local routing decision. Whatever address comes back is, by definition, the one your machine would use to reach the outside world, which is a much better proxy for "the phone on my Wi-Fi can reach this" than blindly picking the first interface in a list.
WSL2 gets its own warning rather than a silent failure. By default WSL2 sits behind NAT, so the address it finds is real but only reachable from inside Windows/WSL itself - no code fix changes that, so wifiler just detects it (checking /proc/version and the WSL_DISTRO_NAME env var) and prints the actual fix: enable WSL2 mirrored networking, or just run the Windows binary directly.
wifiler generates a random session key every time it starts and encodes it into the QR code. There's no config file, no persisted credential, nothing to leak if an old laptop gets sold. Scan the code, get a cookie, keep browsing - the key itself only has to survive the trip from screen to camera.
That said, it's a deliberately modest security model, not a strong one:
I'd rather ship a small tool that's honest about its scope than a slightly bigger one that quietly overpromises.
The one thing wifiler absolutely cannot get wrong is letting a phone browse outside the folder it was launched from. Every path that crosses a request boundary gets checked with filepath.Rel against a known base directory, not a strings.Contains(path, "..") blacklist:
rel, err := filepath.Rel(baseDir, candidate)
if err != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
// reject
}
Blacklisting substrings is the kind of check that looks right and lets something like a URL-encoded traversal or a symlink slip through. Resolving the actual relative path and checking whether it climbs outside the base is the only version of this I trust.
The first multi-device version had a bug that's obvious in hindsight: there was one global "current directory" variable, so if your phone opened a subfolder, everyone else's browser jumped there too. Fine for one person, confusing the moment two devices connect.
The fix was to stop treating the session key and the "which folder am I looking at" state as the same thing. Now there are two cookies: the session key proves you're allowed in at all, and a second, per-device client ID (generated the same way, just for tracking, not authorization) maps to that device's own current directory in a small in-memory map. Opening a folder on one phone no longer moves anyone else's view, and the file-change watcher polls every directory any connected device currently has open, not just one.
SameSite=Strict cookies, but worth revisiting if that ever loosens.None of these are things I'm trying to hide - they're the honest edges of a tool built for a specific, narrow job: get a file from one device to another, on a network you already trust, without asking you to trust anything else.