refactor(db): drop cleartext site/username column refs (columns removed)
User dropped the now-empty cleartext `site` + `username` columns after the §1.3 migration completed. Removed every reference so the code matches the schema: GET emission, POST/PUT/bulk INSERT/UPDATE (columns + params + binds). title/tags cleartext columns still exist and are untouched. decryptEntryMeta defaults e[f]='' for rows without *_enc (notes w/o site), since GET no longer returns the dropped columns. ponytail: contract phase of expand→migrate→contract; only safe because the migration is proven complete (0 cleartext, both accounts). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -118,14 +118,9 @@ begin
|
||||
begin
|
||||
LObj := TJSONObject.Create;
|
||||
LObj.AddPair('id', TJSONNumber.Create(LQ.FieldByName('id').AsInteger));
|
||||
LObj.AddPair('site', LQ.FieldByName('site').AsString);
|
||||
// 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);
|
||||
// Cleartext username: '' for migrated rows (ciphertext lives in
|
||||
// username_enc). Old rows still carry it until the client sweep.
|
||||
LObj.AddPair('username', LQ.FieldByName('username').AsString);
|
||||
// Encrypted username (AES-GCM under the vault key). NULL → JSON null
|
||||
// so the client knows the row isn't migrated yet and falls back to
|
||||
// the cleartext `username` above.
|
||||
if LQ.FieldByName('username_enc').IsNull then
|
||||
LObj.AddPair('username_enc', TJSONNull.Create)
|
||||
else
|
||||
@@ -404,20 +399,17 @@ begin
|
||||
LQ.Connection := DB.Connection;
|
||||
LQ.SQL.Text :=
|
||||
'INSERT INTO vault_entries ' +
|
||||
'(user_id, site, title, username, username_enc, username_iv, ' +
|
||||
'(user_id, title, 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,' +
|
||||
' icon_b64, template, uuid, created_at, updated_at, password_changed_at) ' +
|
||||
'VALUES (:uid, :s, :tt, :u, :uenc, :uiv, :senc, :siv, :tenc, :tiv2, :genc, :giv, ' +
|
||||
'VALUES (:uid, :tt, :uenc, :uiv, :senc, :siv, :tenc, :tiv2, :genc, :giv, ' +
|
||||
' :e, :i, ''client'', :f, :t, :ts, :tiv, :k, ' +
|
||||
' :cf, :cfiv, :ic, :tpl, :uuid, :c, :c2, :c)';
|
||||
LQ.ParamByName('uid').AsInteger := LUserId;
|
||||
LQ.ParamByName('s').AsString := LSite;
|
||||
LQ.ParamByName('tt').AsString := LTitle;
|
||||
LQ.ParamByName('u').AsString := LUser;
|
||||
// Encrypted metadata: NULL when not supplied (pre-migration client or a
|
||||
// row with no value) so GET emits JSON null and the client falls back.
|
||||
// site/username cleartext columns dropped — only *_enc are written.
|
||||
BindNullable(LQ, 'uenc', LUserEnc);
|
||||
BindNullable(LQ, 'uiv', LUserIv);
|
||||
BindNullable(LQ, 'senc', LSiteEnc);
|
||||
@@ -596,7 +588,7 @@ begin
|
||||
if LHasTemplate then LTemplateSet := ', template=:tpl';
|
||||
LQ.SQL.Text :=
|
||||
'UPDATE vault_entries ' +
|
||||
'SET site=:s, title=:tt, username=:u, username_enc=:uenc, username_iv=:uiv, ' +
|
||||
'SET title=:tt, 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, ' +
|
||||
@@ -607,9 +599,7 @@ begin
|
||||
' THEN :c ELSE password_changed_at END' +
|
||||
LTemplateSet + ' ' +
|
||||
'WHERE id=:id AND user_id=:uid';
|
||||
LQ.ParamByName('s').AsString := LSite;
|
||||
LQ.ParamByName('tt').AsString := LTitle;
|
||||
LQ.ParamByName('u').AsString := LUser;
|
||||
BindNullable(LQ, 'uenc', LUserEnc);
|
||||
BindNullable(LQ, 'uiv', LUserIv);
|
||||
BindNullable(LQ, 'senc', LSiteEnc);
|
||||
@@ -1243,12 +1233,12 @@ begin
|
||||
'WHERE user_id = :uid AND uuid = :uuid';
|
||||
LQ.SQL.Text :=
|
||||
'INSERT INTO vault_entries ' +
|
||||
'(user_id, site, title, username, username_enc, username_iv, ' +
|
||||
'(user_id, title, 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,' +
|
||||
' icon_b64, template, uuid, created_at, updated_at) ' +
|
||||
'VALUES (:uid, :s, :tt, :u, :uenc, :uiv, :senc, :siv, :tenc, :tiv2, :genc, :giv, ' +
|
||||
'VALUES (:uid, :tt, :uenc, :uiv, :senc, :siv, :tenc, :tiv2, :genc, :giv, ' +
|
||||
' :e, :i, ''client'', :f, :t, :ts, :tiv, :k, ' +
|
||||
' :cf, :cfiv, :ic, :tpl, :uuid, :c, :c2)';
|
||||
// Declare optional param types ONCE — the prepared statement is
|
||||
@@ -1316,9 +1306,7 @@ begin
|
||||
// row carries site_enc); the client validated before import.
|
||||
|
||||
LQ.ParamByName('uid').AsInteger := LUserId;
|
||||
LQ.ParamByName('s').AsString := LSite;
|
||||
LQ.ParamByName('tt').AsString := LTitle;
|
||||
LQ.ParamByName('u').AsString := LUser;
|
||||
BindNullable(LQ, 'uenc', LUserEnc);
|
||||
BindNullable(LQ, 'uiv', LUserIv);
|
||||
BindNullable(LQ, 'senc', LSiteEnc);
|
||||
|
||||
Reference in New Issue
Block a user