feat(store): a readable copy of a protected store, on request - #102
Merged
Conversation
Getting your own data out in a form you can read had exactly one route:
unprotect(), which rewrites the destination and leaves the real backup
unencrypted until you remember to undo it. That is a dangerous price for
an ordinary question.
exportBackup({ plaintext: true }) writes the same ZIP with
selfstore.json in the clear. The store, its password and its destination
are untouched: what sits on the destination stays encrypted, and the
default export still encrypts.
Two refusals on purpose. Locked, because there is nothing readable to
write. And a requireEncryption store, outright - that flag says this
store never produces cleartext, and an escape hatch would make it a lie.
|
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



First half of the "transparent mode" design that was parked as a draft: make
the plaintext path real and reachable, before deciding anything about flat
files.
The gap
Ask "can I read my own data?" of a protected store and the answer today is
unprotect(). That rewrites the destination, leaves the real backupunencrypted, and stays that way until the user remembers to reverse it. An
ordinary question with a dangerous answer.
What this adds
exportBackup({ plaintext: true })writes the same ZIP withselfstore.jsonin the clear - openable by any tool, diffable by git, readable by the Python
reference reader.
It changes nothing else. The store stays protected, the password is untouched,
and what sits on the destination stays encrypted. The default export still
encrypts; the flag is the only route to cleartext.
Two refusals, both deliberate
While locked: there is nothing readable to write, so it throws
PASSWORD_REQUIREDrather than produce something wrong.On a
requireEncryptionstore: refused outright. That flag is the hostsaying this store never produces cleartext. Adding a way around it would make
the flag a lie, and the guard that already backstopped
exportBlob()now asksthe same question of the explicit request.
Measured while designing this
The format was already half-way there and the draft's premise held: a
password-less backup is generation 1,
encryption: "none", and the app'sdocuments travel clean - the merge clocks ride a separate sidecar, so nothing
of the bookkeeping is mixed into the data.
What the draft had NOT measured, and what matters for the flat-file half:
selfstore.jsonis a single line of minified JSON with every collection in it.For git that is the worst shape there is - each save rewrites the whole file
and
git diffreports one changed line showing nothing. So "git-diffable" isnot free: it needs pretty-printing with sorted keys and a file per collection,
plus something done about
createdAt, which changes on every write and wouldmake a commit out of an unchanged record. That is the real work in the second
half, and it is now written down.
Verification
Gate green, exit 0. 770 tests over 64 files, 4 new: a readable copy comes out
of a protected store while the destination stays encrypted, the default still
encrypts, locked is refused, and
requireEncryptionis refused.Entry under
[Unreleased]; no release.