explewd 121dbe81f1
All checks were successful
Docker / build-and-push (push) Successful in 3m8s
Add a hash-based password bypass link
The upload password gate can now be skipped with a bookmarkable
#psst=<sha256-hash> fragment instead of typing the password each time.
The server accepts either the plaintext password (X-Upload-Password) or
its SHA-256 hash (X-Upload-Password-Hash), compared timing-safely. The
client computes the hash locally after a normal password entry, so the
bypass link never contains the real password — only a one-way digest of
it, kept out of the URL query string (and thus server logs) by living in
the fragment, same as the decryption key.
2026-07-09 19:48:56 +02:00

wisp

Short-lived, end-to-end encrypted file sharing. Send a file to someone who isn't online right now — they get a link, they get the file once, and then it's gone. The server never has the ability to read what it's holding.

Why

flit already does encrypted file transfer between devices, but it's synchronous — both sides have to be online at the same time for the WebRTC handshake. That's fine for "send this to my other laptop right now," and wrong for "here's a file for you, grab it whenever."

wisp is the asynchronous counterpart: upload once, the recipient retrieves later, on their own schedule. That async gap is the one thing flit's architecture (zero server storage, direct P2P) structurally can't do — it requires the server to actually hold ciphertext for a while, which is new territory for this project family, not a variant of something already built.

What it isn't

  • Not zipline. Zipline is persistent link/screenshot hosting — you keep the URL, the file stays. wisp is the opposite: single retrieval, then the file is unrecoverable, by design.
  • Not flit. Flit needs both peers online simultaneously and never stores anything server-side. wisp is deliberately async and requires temporary server-side ciphertext storage.

Core model

  1. Sender encrypts the file client-side (symmetric, libsodium secretbox — same primitive flit's browser client already uses).
  2. Ciphertext uploads to the server. The encryption key never leaves the sender's browser except inside the URL fragment (#key=...), which browsers never transmit in HTTP requests. The server only ever sees opaque bytes.
  3. Sender shares the link through any channel they like.
  4. Recipient opens the link, downloads the ciphertext, decrypts client-side.
  5. On successful decrypt, the client sends a short confirmation to the server. Only then does the server delete the blob.
  6. A TTL (default: a few days) is the backstop for links nobody ever opens, so nothing sits on disk forever.

Full design, including why "delete on first byte served" is the wrong default, is in IMPLEMENTATION.md.

Status

Design only. No code yet.

Description
Short-lived, end-to-end encrypted file sharing. Send a file to someone who isn't online right now — they get a link, they get the file once, and then it's gone. The server never has the ability to read what it's holding.
Readme MIT 84 KiB
Languages
TypeScript 70.7%
CSS 21.4%
Dockerfile 6.6%
HTML 1.3%