Done in https://github.com/badbundle/vault-app/pull/639 (merged as 9fa5c363).
What it adds: EncryptedVaultStore, which is RecordVaultStore persisted to the slot file. Each change is worked out first, then saved under flock:
- Read the file and check the slot's generation.
- Seal the slot at the next generation.
- Write a temp file and
F_FULLFSYNCit. - Read it back and verify it, byte for byte and by decrypting its own slot.
- Rename it over the file, then
F_FULLFSYNCthe directory. - Publish the change.
Failures: anything before the rename leaves the disk and memory as they were. A failed killphrase deletion returns false, exactly like "no match" (C2).
Conflicts: if another writer (AutoFill) saved first, the change is made again on top of that writer's state, up to 3 times. So killphrase deletions and background writes aren't lost.
Temp files: every save first removes stray temp files, under the lock, so a crashed save can't leave an older copy of the vault behind (C6).
Limits: slots stop growing at 4 MiB (a 64 MiB file), and the uncompressed payload is capped at 64 MiB.
Wiping: the decrypted payload JSON is wiped after decoding.
Tests:
- The contract suite also runs against the encrypted store, checking the file matches memory.
- The differential test.
- A failure and a crash at every step, including a failed cleanup.
- Two stores on one file.
- A performance guard at 1,000 items.
Review: a security review of the first version found three should-fixes: the conflict retry, temp cleanup on every save, and wiping. All three were fixed before merging, and a re-review confirmed them. The #633 follow-ups for the header-AAD test, buffer wiping, the growth-length residual and memory bounds are in this PR too.