vault, sftp: a key reads sealed files only when allowed to

Since e4e3e2b every registered SSH key could read sealed files over the
mount while the vault was open in the browser. A key is a standing
credential on another machine, so it now needs vault access, given and
taken per key with :sshkey vault <name> on|off (PATCH /api/ssh-keys/{id},
migration 0016). Existing keys start without it. The access is asked on
every read of a sealed file, so taking it away cuts off a read under way,
as locking does. That includes a write handle opened over a sealed file:
its .part holds the decrypted bytes and could be read back through it.

A mount no longer holds the vault open: it takes the key through the new
Vault::peek_key, which does not count as use. Opening sealed files over
and over from an indexer kept the idle lock from ever firing.

The rest of the audit's findings on this side:
- An unfinished upload's .part is removed when it is dropped, so a sealed
  file's plaintext does not sit in uploads/ after a client goes away.
- A deleted key can no longer write, setstat or close-and-save through a
  session that was already open.
- A session holds at most 256 handles and 64 MiB in memory, the server at
  most 32 connections; keepalives drop a peer that stopped answering.
- A sealed download in the browser ends when the vault locks, the way a
  read over the mount already did.
- Certificate inspection refuses a key or keystore that asks for more
  than ten million rounds, or scrypt beyond 2^20 and r = 8, before running
  the derivation: the file chooses those numbers, and the work could not
  be stopped once begun.
This commit is contained in:
nvrl committed 2026-10-20 11:43:39 +02:00
1 parent f450883ac0
commit a1bc0a9995
11 files changed
+578 -67

No files matched your search

+14 -7
View File
@@ -138,6 +138,7 @@ keys get in, and only the ones registered from inside the workspace:
:sshkey add laptop ssh-ed25519 AAAA… you@laptop
:sshkey lists them, with their fingerprints
:sshkey rm laptop and this one is out, mounted or not
:sshkey vault laptop on this key may read sealed files while the vault is open
```
```sh
@@ -268,13 +269,19 @@ limit at least that large too.
The SFTP mount shows files beside the documents, under their own names — a
later file that shares one is told apart by its id, `slides (42).pdf` — and
anything copied in that is not a `.md` becomes a file in the tree, streamed to
disk under the same size limit. While the vault is open in the browser a
sealed file opens there too, decrypted as it is read, and is sealed again when
it is saved, wherever it sits; a file copied into a sealed folder is sealed on
the way in. While the vault is shut both are refused, and locking it cuts off
a read already under way — though a client that cached what it read keeps
that copy until it lets go of it. Reading over the
mount does not hold the vault open; only the browser and opening a file do.
disk under the same size limit. A file copied into a sealed folder is sealed
on the way in while the vault is open in the browser. Reading one back takes
more: a key is a standing credential kept on another machine, so it reads
sealed files only once given vault access with `:sshkey vault <name> on`, and
none has it to start with. Such a key, while the vault is open, opens a sealed
file decrypted as it is read, and it is sealed again when it is saved,
wherever it sits. While the vault is shut, or once the access is taken away,
both are refused, and either cuts off a read already under way — though a
client that cached what it read keeps that copy until it lets go of it.
Nothing done over the mount holds the vault open; only the browser does. A
session holds at most 256 handles and 64 MB in memory, the server at most 32
connections, and one whose client has stopped answering is dropped within a
few minutes.
Editor droppings — swap files, `~` backups, dotted temp files — stay in
memory for the session, and a dotted temp file renamed onto a real name is kept
as that file, which is how `rsync` and most editors save.