← All posts

Share links, a photo gallery, and encryption by default

Three big things this week, which is unusual. Two are features you'll actually touch — public share links and a real photo gallery — and the third is a default MeshHold should have shipped with: encryption at rest, now on by default. All of it is the pre-0.8 push.

A file shared by a public link through a blind gateway that can't read it

Three big things this week, which is unusual — most weeks have one. Two are features you'll actually touch (sharing, and a real photo gallery), and the third is a default MeshHold should have shipped with from day one (encryption at rest). All of it is the pre-0.8 push.

Share a file — without handing over the keys

You can now create a public link to a file or a whole vault. Someone opens it in a browser, no MeshHold required, and reads or streams what you shared. The interesting part is what the link doesn't leak: the node serving the public gateway never gets the vault key. The share carries its own key, the bytes are transcrypted on the way out, and a protected link derives its unlock from a password you set — Argon2id, run right in the recipient's browser as WebAssembly — before the gateway will serve a single byte. Previews are generated on demand and sealed before they move, so you can hand someone a photo album or a video that plays in-page without them, or the gateway, ever touching the plaintext.

And it goes both ways: a drop link lets someone send a file to you, straight into a vault, with resumable uploads and a per-IP limit so a link can't be turned into a firehose.

Photos got a proper view. It reads EXIF — orientation included, so pictures show up the way the camera was held instead of sideways — draws the grid from sealed thumbnails rather than full originals, lets you select a pile of them and download the lot as one zip, and it's navigable with a TV remote. Best of all it's a single, framework-free gallery core shared across three places: the Files page, the living-room TV, and inside a shared link. Write it once, ship it everywhere.

Encrypted at rest, by default

This one's overdue and I'll own it: until now a node's store was encrypted only if you asked. Now new nodes encrypt by default, and existing ones get a Security panel that tells you plainly whether you're encrypted and offers to convert — with meshhold at-rest doing the same from the terminal, in either direction, because a one-way door is its own kind of trap. The conversion migrates without carrying off the node's identity and, crucially, without leaving a plaintext copy of the database sitting next to the encrypted one. While in there, passwords moved to Argon2id across the board — Web UI login, 2FA recovery codes, all of it — the dead bcrypt path is gone, and on Windows the service's state directory gets locked down with a real ACL so another local user can't read it.

And your config file is yours again

The least glamorous fix of the week is the one I'm happiest about. The daemon used to rewrite config.yaml behind your back — and a bug meant changing one file-send setting could erase most of it. No more: the daemon doesn't write your config, full stop. Runtime state lives in its own store, secrets can come from outside the file, a config write is verified before it lands and keeps a backup, and meshhold config lint will find a typo before it bites. Add a truthful meshhold version that reports the code actually running, cleaner upgrades that stop the service first, and a tray Quit that answers instantly — and that's the incident-proofing a first release needs.

Getting close now.


Since last week

  • Public share links: create / list / revoke links to a file or a vault, served through a blind gateway that never sees the vault key (the share carries its own; bytes are transcrypted); optional password protection derived in-browser with Argon2id (WASM); on-demand sealed previews so albums and videos play in-page; per-IP limits and a size cap
  • Drop links: a link that receives a file into a vault, with resumable uploads held at the holder
  • Photo gallery: an EXIF-aware, correctly-rotated photos view drawn from sealed thumbnails, with multi-select zip download and TV-remote navigation — one framework-free core shared by the Files page, the TV, and shared links
  • Encryption at rest by default: new nodes encrypt on first run; a Security panel + meshhold at-rest convert existing ones either way, migrating without a plaintext leftover; Argon2id for the Web UI password and 2FA recovery codes (the bcrypt path removed); a locked-down state directory on Windows
  • Config.yaml is the operator's: the daemon no longer rewrites it (and no longer erases it on a file-send change); secrets can live outside it; writes are verified and backed up; plus meshhold config lint, a truthful meshhold version, and clearer start-up refusals
  • Obfs-ssh mask: forward non-members to a real sshd (node.obfs.ssh.dest) so a prober meets an ordinary SSH server; a check-ssh-dest to verify it
  • Honest site: three- and five-way comparisons against ownCloud / Nextcloud, an Acceptable Use page, and a pass to stop advertising what we don't ship (UnifiedPush, i18n); the operator now gets mailed when a bug report or a donation lands