← Projects · 2026-07-09

wisp

Short-lived, end-to-end encrypted file sharing. Upload once, the recipient retrieves it later, and then it's gone for good.

Live sitewisp.dev.xplwd.com → Repoexplewd/wisp →

Case study: Case study: wisp

Highlights

  • Client-side libsodium secretbox encryption — the key lives only in the URL fragment, which browsers never send to the server
  • Confirm-token deletion: the server keeps ciphertext until the client confirms a successful decrypt, not on first byte served — the exact bug that made Firefox Send's 'burned before it finished downloading' failure mode possible
  • TTL sweep on an interval independently backstops any link nobody ever opens
  • Filename and content-type live inside the encrypted envelope, not in server-side metadata — the server never learns even the filename
  • Password-gated upload screen, no accounts, configurable via env
  • SQLite + local disk blob storage in a single Docker volume — no external services

The asynchronous counterpart to flit: flit needs both devices online at once for a direct WebRTC transfer and never touches a server disk. wisp is for “here’s a file for you, grab it whenever” — upload once, the recipient retrieves on their own schedule. That async gap is the one thing flit’s architecture structurally can’t do, since it requires the server to actually hold ciphertext for a while.

The server never has the ability to read what it’s holding. The file is encrypted client-side before upload; the key travels only in the link’s URL fragment, which never reaches the server in any HTTP request. What the server sees is opaque bytes, a size, and a countdown.

Each link works exactly once. The design deliberately avoids deleting on first byte served — that’s the bug that made Firefox Send unreliable, where a dropped connection mid-download could burn a link before the file actually arrived. Instead the client confirms a successful decrypt before the server deletes anything; a TTL is the backstop for links nobody ever opens.