fix(sync): preserve created_at/updated_at when sync adds a remote entry

Same class as the reported import bug, other door: POST /entries always
stamped now, so an entry arriving on a device via sync lost its original
creation date (and advertised a fake edit via fresh updated_at).
HandleCreateEntry now honours body timestamps like bulk-import (absent ->
now); applyRemoteSnapshot already ships them through encryptImportEntry,
normalized to the DB format. Regular saves/duplicates send none - unchanged.
password_changed_at shares the created_at param, which is faithful: the
password is at least as old as the entry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-07-13 00:18:13 +01:00
parent 829056f1fa
commit a911f2588f
+11 -3
View File
@@ -327,7 +327,7 @@ var
LBody, LObj: TJSONObject; LBody, LObj: TJSONObject;
LSite, LTitle, LUser, LUserEnc, LUserIv, LFolder, LEnc, LIV, LTags, LNow, LSite, LTitle, LUser, LUserEnc, LUserIv, LFolder, LEnc, LIV, LTags, LNow,
LTotpSec, LTotpIv, LKind, LCf, LCfIv, LIcon, LUuid, LTotpSec, LTotpIv, LKind, LCf, LCfIv, LIcon, LUuid,
LTemplateEnc, LTemplateIv, LTemplateEnc, LTemplateIv, LCreatedAt, LUpdatedAt,
LSiteEnc, LSiteIv, LTitleEnc, LTitleIv, LTagsEnc, LTagsIv: string; LSiteEnc, LSiteIv, LTitleEnc, LTitleIv, LTagsEnc, LTagsIv: string;
LQ: TFDQuery; LQ: TFDQuery;
begin begin
@@ -373,6 +373,12 @@ begin
// identity). Otherwise the server mints a fresh one. // identity). Otherwise the server mints a fresh one.
LUuid := Trim(LBody.GetValue<string>('uuid', '')); LUuid := Trim(LBody.GetValue<string>('uuid', ''));
if LUuid = '' then LUuid := NewUUIDv4; if LUuid = '' then LUuid := NewUUIDv4;
// Preserve original timestamps when the caller carries them (sync adds
// a remote entry via applyRemoteSnapshot -> encryptImportEntry). Same
// contract as bulk-import: absent/empty -> stamp now. Regular saves
// (soSave, duplicate) don't send them, so nothing changes there.
LCreatedAt := Trim(LBody.GetValue<string>('created_at', ''));
LUpdatedAt := Trim(LBody.GetValue<string>('updated_at', ''));
finally finally
LBody.Free; LBody.Free;
end; end;
@@ -445,8 +451,10 @@ begin
BindNullable(LQ, 'tplenc', LTemplateEnc); BindNullable(LQ, 'tplenc', LTemplateEnc);
BindNullable(LQ, 'tpliv', LTemplateIv); BindNullable(LQ, 'tpliv', LTemplateIv);
LQ.ParamByName('uuid').AsString := LUuid; LQ.ParamByName('uuid').AsString := LUuid;
LQ.ParamByName('c').AsString := LNow; if LCreatedAt = '' then LCreatedAt := LNow;
LQ.ParamByName('c2').AsString := LNow; if LUpdatedAt = '' then LUpdatedAt := LNow;
LQ.ParamByName('c').AsString := LCreatedAt;
LQ.ParamByName('c2').AsString := LUpdatedAt;
LQ.ExecSQL; LQ.ExecSQL;
LNewId := DB.Connection.GetLastAutoGenValue('vault_entries'); LNewId := DB.Connection.GetLastAutoGenValue('vault_entries');