Asked for explicitly, a round after the machinery landed. `AutoLogin::
remember` is now the one write path the login screen uses, and it stores
`password_encrypted` — the authenticated blob of `credential.rs`, keyed
on 32 random bytes in a separate 0600 file. `migrate_plaintext` upgrades
a file written by an older build on the next launch, and the plaintext
field stays *readable* so that upgrade cannot lock anyone out of a store
they already had.
Two decisions inside it, both places where the convenient answer is the
wrong one:
A password that cannot be encrypted is **not stored at all** — there is
no fallback to the clear field. The player cannot see the difference
between a box that wrote a blob and one that quietly wrote plaintext, so
a silent downgrade is worse than a box that visibly did not take.
A stale plaintext field beside a blob is **cleared, not encrypted**:
`effective_password` never read it, so encrypting it would promote a
password the player has already replaced.
What changed is the file. What did not is the threat model: the blob
answers the file being read by another account, copied into a backup or
pasted into a bug report, and cannot answer anything running as this
user — the point of the feature is logging in without typing a secret,
so no secret of the player's is in the chain to key it on. Both files
are 0600 from their first byte.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn