From a911f2588fa0eb54e1478508b9af0c06eff11568 Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Mon, 13 Jul 2026 00:18:13 +0100 Subject: [PATCH] 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 --- delphi-backend/Handlers/PM.Handler.Entries.pas | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/delphi-backend/Handlers/PM.Handler.Entries.pas b/delphi-backend/Handlers/PM.Handler.Entries.pas index b23293d..11296c5 100644 --- a/delphi-backend/Handlers/PM.Handler.Entries.pas +++ b/delphi-backend/Handlers/PM.Handler.Entries.pas @@ -327,7 +327,7 @@ var LBody, LObj: TJSONObject; LSite, LTitle, LUser, LUserEnc, LUserIv, LFolder, LEnc, LIV, LTags, LNow, LTotpSec, LTotpIv, LKind, LCf, LCfIv, LIcon, LUuid, - LTemplateEnc, LTemplateIv, + LTemplateEnc, LTemplateIv, LCreatedAt, LUpdatedAt, LSiteEnc, LSiteIv, LTitleEnc, LTitleIv, LTagsEnc, LTagsIv: string; LQ: TFDQuery; begin @@ -373,6 +373,12 @@ begin // identity). Otherwise the server mints a fresh one. LUuid := Trim(LBody.GetValue('uuid', '')); 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('created_at', '')); + LUpdatedAt := Trim(LBody.GetValue('updated_at', '')); finally LBody.Free; end; @@ -445,8 +451,10 @@ begin BindNullable(LQ, 'tplenc', LTemplateEnc); BindNullable(LQ, 'tpliv', LTemplateIv); LQ.ParamByName('uuid').AsString := LUuid; - LQ.ParamByName('c').AsString := LNow; - LQ.ParamByName('c2').AsString := LNow; + if LCreatedAt = '' then LCreatedAt := LNow; + if LUpdatedAt = '' then LUpdatedAt := LNow; + LQ.ParamByName('c').AsString := LCreatedAt; + LQ.ParamByName('c2').AsString := LUpdatedAt; LQ.ExecSQL; LNewId := DB.Connection.GetLastAutoGenValue('vault_entries');