From 65230a9c3e7c03cdaecb166df20073d5c7dcc64f Mon Sep 17 00:00:00 2001 From: Shane Melton Date: Fri, 22 Aug 2025 12:21:23 -0700 Subject: [PATCH] [PM-24229] Preserve existing cipher date fields when using CipherExport.toView (#15993) * [PM-24229] Ensure existing dates are persisted when using CipherExport.toView * [PM-24229] Test both null and undefined * [PM-24229] Add test for copied date values --- .../src/models/export/cipher.export.spec.ts | 44 +++++++++++++++++++ .../common/src/models/export/cipher.export.ts | 6 +-- 2 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 libs/common/src/models/export/cipher.export.spec.ts diff --git a/libs/common/src/models/export/cipher.export.spec.ts b/libs/common/src/models/export/cipher.export.spec.ts new file mode 100644 index 00000000000..42c01ccef15 --- /dev/null +++ b/libs/common/src/models/export/cipher.export.spec.ts @@ -0,0 +1,44 @@ +import { CipherExport } from "@bitwarden/common/models/export/cipher.export"; +import { SecureNoteExport } from "@bitwarden/common/models/export/secure-note.export"; +import { CipherType } from "@bitwarden/common/vault/enums"; +import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; + +describe("Cipher Export", () => { + describe("toView", () => { + it.each([[null], [undefined]])( + "should preserve existing date values when request dates are nullish (=%p)", + (nullishDate) => { + const existingView = new CipherView(); + existingView.creationDate = new Date("2023-01-01T00:00:00Z"); + existingView.revisionDate = new Date("2023-01-02T00:00:00Z"); + existingView.deletedDate = new Date("2023-01-03T00:00:00Z"); + + const request = CipherExport.template(); + request.type = CipherType.SecureNote; + request.secureNote = SecureNoteExport.template(); + request.creationDate = nullishDate as any; + request.revisionDate = nullishDate as any; + request.deletedDate = nullishDate as any; + + const resultView = CipherExport.toView(request, existingView); + expect(resultView.creationDate).toEqual(existingView.creationDate); + expect(resultView.revisionDate).toEqual(existingView.revisionDate); + expect(resultView.deletedDate).toEqual(existingView.deletedDate); + }, + ); + + it("should set date values when request dates are provided", () => { + const request = CipherExport.template(); + request.type = CipherType.SecureNote; + request.secureNote = SecureNoteExport.template(); + request.creationDate = new Date("2023-01-01T00:00:00Z"); + request.revisionDate = new Date("2023-01-02T00:00:00Z"); + request.deletedDate = new Date("2023-01-03T00:00:00Z"); + + const resultView = CipherExport.toView(request); + expect(resultView.creationDate).toEqual(request.creationDate); + expect(resultView.revisionDate).toEqual(request.revisionDate); + expect(resultView.deletedDate).toEqual(request.deletedDate); + }); + }); +}); diff --git a/libs/common/src/models/export/cipher.export.ts b/libs/common/src/models/export/cipher.export.ts index d343621328c..846a56dac85 100644 --- a/libs/common/src/models/export/cipher.export.ts +++ b/libs/common/src/models/export/cipher.export.ts @@ -81,9 +81,9 @@ export class CipherExport { view.passwordHistory = req.passwordHistory.map((ph) => PasswordHistoryExport.toView(ph)); } - view.creationDate = req.creationDate ? new Date(req.creationDate) : null; - view.revisionDate = req.revisionDate ? new Date(req.revisionDate) : null; - view.deletedDate = req.deletedDate ? new Date(req.deletedDate) : null; + view.creationDate = req.creationDate ? new Date(req.creationDate) : view.creationDate; + view.revisionDate = req.revisionDate ? new Date(req.revisionDate) : view.revisionDate; + view.deletedDate = req.deletedDate ? new Date(req.deletedDate) : view.deletedDate; return view; }