1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-04 17:43:39 +00:00

[EC-582] Add domain object serialization (#3623)

This commit is contained in:
Thomas Rittson
2022-10-04 06:50:43 +10:00
committed by GitHub
parent cb7b8313a4
commit 162db0b600
25 changed files with 513 additions and 16 deletions

View File

@@ -8,7 +8,7 @@ import { EncString } from "@bitwarden/common/models/domain/encString";
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetricCryptoKey";
import { ContainerService } from "@bitwarden/common/services/container.service";
import { makeStaticByteArray, mockEnc } from "../../utils";
import { makeStaticByteArray, mockEnc, mockFromJson } from "../../utils";
describe("Attachment", () => {
let data: AttachmentData;
@@ -131,4 +131,25 @@ describe("Attachment", () => {
});
});
});
describe("fromJSON", () => {
it("initializes nested objects", () => {
jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson);
const actual = Attachment.fromJSON({
key: "myKey",
fileName: "myFileName",
});
expect(actual).toEqual({
key: "myKey_fromJSON",
fileName: "myFileName_fromJSON",
});
expect(actual).toBeInstanceOf(Attachment);
});
it("returns null if object is null", () => {
expect(Attachment.fromJSON(null)).toBeNull();
});
});
});

View File

@@ -1,7 +1,8 @@
import { CardData } from "@bitwarden/common/models/data/cardData";
import { Card } from "@bitwarden/common/models/domain/card";
import { EncString } from "@bitwarden/common/models/domain/encString";
import { mockEnc } from "../../utils";
import { mockEnc, mockFromJson } from "../../utils";
describe("Card", () => {
let data: CardData;
@@ -70,4 +71,33 @@ describe("Card", () => {
expYear: "expYear",
});
});
describe("fromJSON", () => {
it("initializes nested objects", () => {
jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson);
const actual = Card.fromJSON({
cardholderName: "mockCardHolder",
brand: "mockBrand",
number: "mockNumber",
expMonth: "mockExpMonth",
expYear: "mockExpYear",
code: "mockCode",
});
expect(actual).toEqual({
cardholderName: "mockCardHolder_fromJSON",
brand: "mockBrand_fromJSON",
number: "mockNumber_fromJSON",
expMonth: "mockExpMonth_fromJSON",
expYear: "mockExpYear_fromJSON",
code: "mockCode_fromJSON",
});
expect(actual).toBeInstanceOf(Card);
});
it("returns null if object is null", () => {
expect(Card.fromJSON(null)).toBeNull();
});
});
});

View File

@@ -1,4 +1,5 @@
import { Substitute, Arg } from "@fluffy-spoon/substitute";
import { Jsonify } from "type-fest";
import { CipherRepromptType } from "@bitwarden/common/enums/cipherRepromptType";
import { CipherType } from "@bitwarden/common/enums/cipherType";
@@ -6,16 +7,20 @@ import { FieldType } from "@bitwarden/common/enums/fieldType";
import { SecureNoteType } from "@bitwarden/common/enums/secureNoteType";
import { UriMatchType } from "@bitwarden/common/enums/uriMatchType";
import { CipherData } from "@bitwarden/common/models/data/cipherData";
import { Attachment } from "@bitwarden/common/models/domain/attachment";
import { Card } from "@bitwarden/common/models/domain/card";
import { Cipher } from "@bitwarden/common/models/domain/cipher";
import { EncString } from "@bitwarden/common/models/domain/encString";
import { Field } from "@bitwarden/common/models/domain/field";
import { Identity } from "@bitwarden/common/models/domain/identity";
import { Login } from "@bitwarden/common/models/domain/login";
import { Password } from "@bitwarden/common/models/domain/password";
import { SecureNote } from "@bitwarden/common/models/domain/secureNote";
import { CardView } from "@bitwarden/common/models/view/cardView";
import { IdentityView } from "@bitwarden/common/models/view/identityView";
import { LoginView } from "@bitwarden/common/models/view/loginView";
import { mockEnc } from "../../utils";
import { mockEnc, mockFromJson } from "../../utils";
describe("Cipher DTO", () => {
it("Convert from empty CipherData", () => {
@@ -587,4 +592,63 @@ describe("Cipher DTO", () => {
});
});
});
describe("fromJSON", () => {
it("initializes nested objects", () => {
jest.spyOn(Attachment, "fromJSON").mockImplementation(mockFromJson);
jest.spyOn(Field, "fromJSON").mockImplementation(mockFromJson);
jest.spyOn(Password, "fromJSON").mockImplementation(mockFromJson);
jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson);
const revisionDate = new Date("2022-08-04T01:06:40.441Z");
const deletedDate = new Date("2022-09-04T01:06:40.441Z");
const actual = Cipher.fromJSON({
name: "myName",
notes: "myNotes",
revisionDate: revisionDate.toISOString(),
attachments: ["attachment1", "attachment2"] as any,
fields: ["field1", "field2"] as any,
passwordHistory: ["ph1", "ph2"] as any,
deletedDate: deletedDate.toISOString(),
} as Jsonify<Cipher>);
expect(actual).toMatchObject({
name: "myName_fromJSON",
notes: "myNotes_fromJSON",
revisionDate: revisionDate,
attachments: ["attachment1_fromJSON", "attachment2_fromJSON"],
fields: ["field1_fromJSON", "field2_fromJSON"],
passwordHistory: ["ph1_fromJSON", "ph2_fromJSON"],
deletedDate: deletedDate,
});
expect(actual).toBeInstanceOf(Cipher);
});
test.each([
// Test description, CipherType, expected output
["LoginView", CipherType.Login, { login: "myLogin_fromJSON" }],
["CardView", CipherType.Card, { card: "myCard_fromJSON" }],
["IdentityView", CipherType.Identity, { identity: "myIdentity_fromJSON" }],
["Secure Note", CipherType.SecureNote, { secureNote: "mySecureNote_fromJSON" }],
])("initializes %s", (description: string, cipherType: CipherType, expected: any) => {
jest.spyOn(Login, "fromJSON").mockImplementation(mockFromJson);
jest.spyOn(Identity, "fromJSON").mockImplementation(mockFromJson);
jest.spyOn(Card, "fromJSON").mockImplementation(mockFromJson);
jest.spyOn(SecureNote, "fromJSON").mockImplementation(mockFromJson);
const actual = Cipher.fromJSON({
login: "myLogin",
card: "myCard",
identity: "myIdentity",
secureNote: "mySecureNote",
type: cipherType,
} as any);
expect(actual).toMatchObject(expected);
});
it("returns null if object is null", () => {
expect(Cipher.fromJSON(null)).toBeNull();
});
});
});

View File

@@ -226,5 +226,9 @@ describe("EncString", () => {
expect(encString.toJSON()).toBe(encString.encryptedString);
});
it("returns null if object is null", () => {
expect(EncString.fromJSON(null)).toBeNull();
});
});
});

View File

@@ -1,8 +1,9 @@
import { FieldType } from "@bitwarden/common/enums/fieldType";
import { FieldData } from "@bitwarden/common/models/data/fieldData";
import { EncString } from "@bitwarden/common/models/domain/encString";
import { Field } from "@bitwarden/common/models/domain/field";
import { mockEnc } from "../../utils";
import { mockEnc, mockFromJson } from "../../utils";
describe("Field", () => {
let data: FieldData;
@@ -61,4 +62,25 @@ describe("Field", () => {
showValue: false,
});
});
describe("fromJSON", () => {
it("initializes nested objects", () => {
jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson);
const actual = Field.fromJSON({
name: "myName",
value: "myValue",
});
expect(actual).toEqual({
name: "myName_fromJSON",
value: "myValue_fromJSON",
});
expect(actual).toBeInstanceOf(Field);
});
it("returns null if object is null", () => {
expect(Field.fromJSON(null)).toBeNull();
});
});
});

View File

@@ -2,7 +2,7 @@ import { FolderData } from "@bitwarden/common/models/data/folderData";
import { EncString } from "@bitwarden/common/models/domain/encString";
import { Folder } from "@bitwarden/common/models/domain/folder";
import { mockEnc } from "../../utils";
import { mockEnc, mockFromJson } from "../../utils";
describe("Folder", () => {
let data: FolderData;
@@ -42,7 +42,6 @@ describe("Folder", () => {
describe("fromJSON", () => {
jest.mock("@bitwarden/common/models/domain/encString");
const mockFromJson = (stub: any) => (stub + "_fromJSON") as any;
jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson);
it("initializes nested objects", () => {

View File

@@ -1,7 +1,8 @@
import { IdentityData } from "@bitwarden/common/models/data/identityData";
import { EncString } from "@bitwarden/common/models/domain/encString";
import { Identity } from "@bitwarden/common/models/domain/identity";
import { mockEnc } from "../../utils";
import { mockEnc, mockFromJson } from "../../utils";
describe("Identity", () => {
let data: IdentityData;
@@ -131,4 +132,57 @@ describe("Identity", () => {
username: "mockUsername",
});
});
describe("fromJSON", () => {
it("initializes nested objects", () => {
jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson);
const actual = Identity.fromJSON({
firstName: "mockFirstName",
lastName: "mockLastName",
address1: "mockAddress1",
address2: "mockAddress2",
address3: "mockAddress3",
city: "mockCity",
company: "mockCompany",
country: "mockCountry",
email: "mockEmail",
licenseNumber: "mockLicenseNumber",
middleName: "mockMiddleName",
passportNumber: "mockPassportNumber",
phone: "mockPhone",
postalCode: "mockPostalCode",
ssn: "mockSsn",
state: "mockState",
title: "mockTitle",
username: "mockUsername",
});
expect(actual).toEqual({
firstName: "mockFirstName_fromJSON",
lastName: "mockLastName_fromJSON",
address1: "mockAddress1_fromJSON",
address2: "mockAddress2_fromJSON",
address3: "mockAddress3_fromJSON",
city: "mockCity_fromJSON",
company: "mockCompany_fromJSON",
country: "mockCountry_fromJSON",
email: "mockEmail_fromJSON",
licenseNumber: "mockLicenseNumber_fromJSON",
middleName: "mockMiddleName_fromJSON",
passportNumber: "mockPassportNumber_fromJSON",
phone: "mockPhone_fromJSON",
postalCode: "mockPostalCode_fromJSON",
ssn: "mockSsn_fromJSON",
state: "mockState_fromJSON",
title: "mockTitle_fromJSON",
username: "mockUsername_fromJSON",
});
expect(actual).toBeInstanceOf(Identity);
});
it("returns null if object is null", () => {
expect(Identity.fromJSON(null)).toBeNull();
});
});
});

View File

@@ -2,11 +2,12 @@ import { Substitute, Arg } from "@fluffy-spoon/substitute";
import { UriMatchType } from "@bitwarden/common/enums/uriMatchType";
import { LoginData } from "@bitwarden/common/models/data/loginData";
import { EncString } from "@bitwarden/common/models/domain/encString";
import { Login } from "@bitwarden/common/models/domain/login";
import { LoginUri } from "@bitwarden/common/models/domain/loginUri";
import { LoginUriView } from "@bitwarden/common/models/view/loginUriView";
import { mockEnc } from "../../utils";
import { mockEnc, mockFromJson } from "../../utils";
describe("Login DTO", () => {
it("Convert from empty LoginData", () => {
@@ -98,4 +99,33 @@ describe("Login DTO", () => {
expect(loginData).toEqual(data);
});
describe("fromJSON", () => {
it("initializes nested objects", () => {
jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson);
jest.spyOn(LoginUri, "fromJSON").mockImplementation(mockFromJson);
const passwordRevisionDate = new Date("2022-01-31T12:00:00.000Z");
const actual = Login.fromJSON({
uris: ["loginUri1", "loginUri2"] as any,
username: "myUsername",
password: "myPassword",
passwordRevisionDate: passwordRevisionDate.toISOString(),
totp: "myTotp",
});
expect(actual).toEqual({
uris: ["loginUri1_fromJSON", "loginUri2_fromJSON"] as any,
username: "myUsername_fromJSON",
password: "myPassword_fromJSON",
passwordRevisionDate: passwordRevisionDate,
totp: "myTotp_fromJSON",
});
expect(actual).toBeInstanceOf(Login);
});
it("returns null if object is null", () => {
expect(Login.fromJSON(null)).toBeNull();
});
});
});

View File

@@ -1,8 +1,11 @@
import { Jsonify } from "type-fest";
import { UriMatchType } from "@bitwarden/common/enums/uriMatchType";
import { LoginUriData } from "@bitwarden/common/models/data/loginUriData";
import { EncString } from "@bitwarden/common/models/domain/encString";
import { LoginUri } from "@bitwarden/common/models/domain/loginUri";
import { mockEnc } from "../../utils";
import { mockEnc, mockFromJson } from "../../utils";
describe("LoginUri", () => {
let data: LoginUriData;
@@ -54,4 +57,23 @@ describe("LoginUri", () => {
match: 3,
});
});
describe("fromJSON", () => {
it("initializes nested objects", () => {
jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson);
const actual = LoginUri.fromJSON({
uri: "myUri",
} as Jsonify<LoginUri>);
expect(actual).toEqual({
uri: "myUri_fromJSON",
});
expect(actual).toBeInstanceOf(LoginUri);
});
it("returns null if object is null", () => {
expect(LoginUri.fromJSON(null)).toBeNull();
});
});
});

View File

@@ -1,7 +1,8 @@
import { PasswordHistoryData } from "@bitwarden/common/models/data/passwordHistoryData";
import { EncString } from "@bitwarden/common/models/domain/encString";
import { Password } from "@bitwarden/common/models/domain/password";
import { mockEnc } from "../../utils";
import { mockEnc, mockFromJson } from "../../utils";
describe("Password", () => {
let data: PasswordHistoryData;
@@ -48,4 +49,26 @@ describe("Password", () => {
lastUsedDate: new Date("2022-01-31T12:00:00.000Z"),
});
});
describe("fromJSON", () => {
it("initializes nested objects", () => {
jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson);
const lastUsedDate = new Date("2022-01-31T12:00:00.000Z");
const actual = Password.fromJSON({
password: "myPassword",
lastUsedDate: lastUsedDate.toISOString(),
});
expect(actual).toEqual({
password: "myPassword_fromJSON",
lastUsedDate: lastUsedDate,
});
expect(actual).toBeInstanceOf(Password);
});
it("returns null if object is null", () => {
expect(Password.fromJSON(null)).toBeNull();
});
});
});

View File

@@ -43,4 +43,10 @@ describe("SecureNote", () => {
type: 0,
});
});
describe("fromJSON", () => {
it("returns null if object is null", () => {
expect(SecureNote.fromJSON(null)).toBeNull();
});
});
});