feat(crypto): encrypt site/title/tags at rest too (CODE_AUDIT §1.3)
Extends the username-at-rest scheme to site, title and tags — the last searchable metadata still stored cleartext. Same design: dedicated <f>_enc/<f>_iv columns (AES-GCM under the vault key), decrypted at load into e.<f>, so client-side search/sort/render/favicon/autofill-match are unchanged. Full-strength random-IV AES-GCM (no searchable encryption) because search is client-side. Generalized the helpers over ENCRYPTED_META_FIELDS = [username, site, title, tags]: - withEncryptedUsername → withEncryptedMeta (encrypts all four, blanks cleartext) — wraps every POST/PUT body. - decryptEntryUsernames → decryptEntryMeta (decrypts all four at load). - migrateUsernamesAtRest → migrateMetadataAtRest (sweeps any field still cleartext, live + trash). - doChangeMasterPassword re-encrypts all four under the new key. Server (Entries + Auth + Database): - Columns site_enc/iv, title_enc/iv, tags_enc/iv; GET emits them (new AddNullableField helper); POST/PUT/bulk read+persist (BindNullable helper); rotation UPDATE re-encrypts them. - Removed the server "Site required" validation (site='' when encrypted — the client enforces it) at POST/PUT/bulk. - ?q= server search neutralized (site+username ciphertext → LIKE useless; the frontend never sends ?search=). Tests: merge assertions updated to decrypt site (encrypted on import). 65/65. username was runtime-validated earlier; site/title/tags NOT yet compiled/ runtime-tested (Delphi) — large multi-handler change. Rebuild BuildAssets + PMServer, then create/edit/dup/move/tag/import/rotate and verify the DB shows no cleartext site/title/tags (and the app still renders/searches). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -456,7 +456,7 @@ async function encryptImportEntry(plain) {
|
||||
: (plain.tags || '');
|
||||
// Encrypt the username at rest (username_enc/username_iv, cleartext blanked)
|
||||
// via the shared choke point in app.js — same as the interactive save path.
|
||||
return await withEncryptedUsername({
|
||||
return await withEncryptedMeta({
|
||||
uuid: plain.uuid || '',
|
||||
site: plain.site,
|
||||
title: plain.title || '',
|
||||
|
||||
Reference in New Issue
Block a user