2.6 KiB
Structured entry documents
crates/storage::document exposes arbitrary password-store entries as ordered,
presentation-neutral documents. Frontends supply a logical entry path and a
secret provider to EntryDocumentService::open; storage resolves and reads the
entry, decrypts it, parses it, and returns fields with stable in-document IDs.
Frontends never inspect .gpg files, select recipients, parse entry text, or
write the repository.
The first physical line is always the conventional password field. Every later
physical line remains independently addressable and is classified as a dynamic
name: value field, valid otpauth:// URI, blank line, or free-form note.
Recognized username, email and URL names receive semantic kinds. Passwords,
OTP URIs, notes and unknown/custom values are sensitive by default; ordinary
identity/navigation fields and blank lines receive separate sensitivity
metadata. Duplicate names are retained as distinct fields in their original
order. Unicode names and values are supported, while non-UTF-8 or otherwise
unrecognized lines remain lossless notes.
Line contents and their LF, CRLF or absent final endings are retained exactly.
Parsing and serializing an untouched document therefore returns byte-identical
plaintext, including mixed endings, empty values, blank lines and a missing
first line. Updates replace only the selected line. Structural operations keep
untouched line bytes and preserve the document's final-newline convention;
new dynamic fields serialize as the upstream-compatible name: value form.
No IDs or metadata are written to the password entry, so this does not create a
new on-disk format. IDs are stable for the lifetime of the opened document and
remain attached to fields through update and reorder operations.
Documents support indexed add, ID-based update and removal, ID-based reorder,
lossless serialization and a redacted conflict token derived from the original
ciphertext. EntryDocumentService::save consumes the edited document and uses
the existing VaultWriter edit session. It rechecks the original ciphertext,
resolves the current recipient policy in storage, encrypts, atomically replaces
the .gpg entry, and performs the storage mutation commit. Concurrent changes
are rejected before writing. A commit failure restores the original encrypted
entry, so clients never receive a successful save for an uncommitted or partial
mutation.
Compatibility tests round-trip every checked-in upstream-compatible fixture and separately cover duplicate keys, Unicode, CRLF, multiline notes, empty values, OTP URIs, blank and missing first lines, stable IDs, reorder, creation, stale documents and commit rollback.