From 94ebc96d7336091c43b379c4ecf789935fb313fa Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:29:06 +0100 Subject: [PATCH] refactor(db): drop cleartext title/tags column refs (columns removed) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User dropped the title + tags cleartext columns too — all four searchable metadata columns are now gone. Removed their refs from GET emission and the POST/PUT/bulk INSERT/UPDATE (columns + params + binds). Only *_enc columns remain; the client reads everything via decryptEntryMeta. Co-Authored-By: Claude Opus 4.8 --- .../Handlers/PM.Handler.Entries.pas | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/delphi-backend/Handlers/PM.Handler.Entries.pas b/delphi-backend/Handlers/PM.Handler.Entries.pas index f412029..b93a815 100644 --- a/delphi-backend/Handlers/PM.Handler.Entries.pas +++ b/delphi-backend/Handlers/PM.Handler.Entries.pas @@ -118,9 +118,8 @@ begin begin LObj := TJSONObject.Create; LObj.AddPair('id', TJSONNumber.Create(LQ.FieldByName('id').AsInteger)); - // site + username cleartext columns were dropped — client reads them - // from *_enc only (decryptEntryMeta). title/tags cleartext still exist. - LObj.AddPair('title', LQ.FieldByName('title').AsString); + // site/username/title/tags cleartext columns dropped — the client + // reads them from *_enc only (decryptEntryMeta). if LQ.FieldByName('username_enc').IsNull then LObj.AddPair('username_enc', TJSONNull.Create) else @@ -148,7 +147,6 @@ begin LObj.AddPair('deleted_at', ISODateTimeField(LQ.FieldByName('deleted_at'))); LObj.AddPair('favorite', TJSONNumber.Create(LQ.FieldByName('favorite').AsInteger)); LObj.AddPair('pinned', TJSONNumber.Create(LQ.FieldByName('pinned').AsInteger)); - LObj.AddPair('tags', LQ.FieldByName('tags').AsString); // TOTP fields are NULL when the entry has no 2FA configured. We emit // JSON null instead of '' so the client can distinguish "no TOTP" from // "TOTP configured with empty ciphertext" (which shouldn't happen). @@ -399,17 +397,16 @@ begin LQ.Connection := DB.Connection; LQ.SQL.Text := 'INSERT INTO vault_entries ' + - '(user_id, title, username_enc, username_iv, ' + + '(user_id, username_enc, username_iv, ' + ' site_enc, site_iv, title_enc, title_iv, tags_enc, tags_iv, ' + ' encrypted_password, iv, encryption_method, ' + - ' folder, tags, totp_secret, totp_iv, kind, custom_fields, custom_fields_iv,' + + ' folder, totp_secret, totp_iv, kind, custom_fields, custom_fields_iv,' + ' icon_b64, template, uuid, created_at, updated_at, password_changed_at) ' + - 'VALUES (:uid, :tt, :uenc, :uiv, :senc, :siv, :tenc, :tiv2, :genc, :giv, ' + - ' :e, :i, ''client'', :f, :t, :ts, :tiv, :k, ' + + 'VALUES (:uid, :uenc, :uiv, :senc, :siv, :tenc, :tiv2, :genc, :giv, ' + + ' :e, :i, ''client'', :f, :ts, :tiv, :k, ' + ' :cf, :cfiv, :ic, :tpl, :uuid, :c, :c2, :c)'; LQ.ParamByName('uid').AsInteger := LUserId; - LQ.ParamByName('tt').AsString := LTitle; - // site/username cleartext columns dropped — only *_enc are written. + // site/username/title/tags cleartext columns dropped — only *_enc written. BindNullable(LQ, 'uenc', LUserEnc); BindNullable(LQ, 'uiv', LUserIv); BindNullable(LQ, 'senc', LSiteEnc); @@ -421,7 +418,6 @@ begin LQ.ParamByName('e').AsString := LEnc; LQ.ParamByName('i').AsString := LIV; LQ.ParamByName('f').AsString := LFolder; - LQ.ParamByName('t').AsString := LTags; // FireDAC needs an explicit DataType on params that are sometimes // assigned a string and sometimes Clear()ed to NULL — without a // prior typed assignment, .Clear raises "data type unknown" on @@ -588,18 +584,18 @@ begin if LHasTemplate then LTemplateSet := ', template=:tpl'; LQ.SQL.Text := 'UPDATE vault_entries ' + - 'SET title=:tt, username_enc=:uenc, username_iv=:uiv, ' + + 'SET username_enc=:uenc, username_iv=:uiv, ' + ' site_enc=:senc, site_iv=:siv, title_enc=:tenc, title_iv=:tiv2, ' + ' tags_enc=:genc, tags_iv=:giv, ' + ' encrypted_password=:e, iv=:i, ' + - ' folder=:f, tags=:t, totp_secret=:ts, totp_iv=:tiv, kind=:k, ' + + ' folder=:f, totp_secret=:ts, totp_iv=:tiv, kind=:k, ' + ' custom_fields=:cf, custom_fields_iv=:cfiv, ' + ' updated_at=:c, ' + ' password_changed_at = CASE WHEN encrypted_password <> :e ' + ' THEN :c ELSE password_changed_at END' + LTemplateSet + ' ' + 'WHERE id=:id AND user_id=:uid'; - LQ.ParamByName('tt').AsString := LTitle; + // site/username/title/tags cleartext columns dropped — only *_enc written. BindNullable(LQ, 'uenc', LUserEnc); BindNullable(LQ, 'uiv', LUserIv); BindNullable(LQ, 'senc', LSiteEnc); @@ -611,7 +607,6 @@ begin LQ.ParamByName('e').AsString := LEnc; LQ.ParamByName('i').AsString := LIV; LQ.ParamByName('f').AsString := LFolder; - LQ.ParamByName('t').AsString := LTags; // Declare TOTP param types so .Clear works on first use (FireDAC // needs an inferred or explicit DataType before NULL binding). LQ.ParamByName('ts').DataType := ftMemo; @@ -1233,13 +1228,13 @@ begin 'WHERE user_id = :uid AND uuid = :uuid'; LQ.SQL.Text := 'INSERT INTO vault_entries ' + - '(user_id, title, username_enc, username_iv, ' + + '(user_id, username_enc, username_iv, ' + ' site_enc, site_iv, title_enc, title_iv, tags_enc, tags_iv, ' + ' encrypted_password, iv, encryption_method, ' + - ' folder, tags, totp_secret, totp_iv, kind, custom_fields, custom_fields_iv,' + + ' folder, totp_secret, totp_iv, kind, custom_fields, custom_fields_iv,' + ' icon_b64, template, uuid, created_at, updated_at) ' + - 'VALUES (:uid, :tt, :uenc, :uiv, :senc, :siv, :tenc, :tiv2, :genc, :giv, ' + - ' :e, :i, ''client'', :f, :t, :ts, :tiv, :k, ' + + 'VALUES (:uid, :uenc, :uiv, :senc, :siv, :tenc, :tiv2, :genc, :giv, ' + + ' :e, :i, ''client'', :f, :ts, :tiv, :k, ' + ' :cf, :cfiv, :ic, :tpl, :uuid, :c, :c2)'; // Declare optional param types ONCE — the prepared statement is // reused across every imported entry, and FireDAC needs the @@ -1306,7 +1301,6 @@ begin // row carries site_enc); the client validated before import. LQ.ParamByName('uid').AsInteger := LUserId; - LQ.ParamByName('tt').AsString := LTitle; BindNullable(LQ, 'uenc', LUserEnc); BindNullable(LQ, 'uiv', LUserIv); BindNullable(LQ, 'senc', LSiteEnc); @@ -1318,7 +1312,6 @@ begin LQ.ParamByName('e').AsString := LEnc; LQ.ParamByName('i').AsString := LIV; LQ.ParamByName('f').AsString := LFolder; - LQ.ParamByName('t').AsString := LTags; if LTotpSec = '' then LQ.ParamByName('ts').Clear else LQ.ParamByName('ts').Value := LTotpSec; if LTotpIv = '' then LQ.ParamByName('tiv').Clear