1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-10 05:13:29 +00:00

[PM-25682] Migrate CipherView and subviews to be TS strict compliant (#16463)

* [PM-25682] Remove ts-strict-ignore from Vault view models and update types to be strict

* [PM-25682] Ignore ViewEncryptableKeys error for old decrypt methods

* [PM-25682] Add null/undefined as possible types for isNull* and other helpers that include null checks internally

* [PM-25682] Use patchValue instead of setValue which does not support undefined values

* [PM-25682] Add type assertions and other misc. null checks where necessary

* [PM-25682] Fix importers specs

* [PM-25682] Cleanup card view/details

* [PM-25682] Fix cipher view hasAttachment helper

* [PM-25682] Cleanup unecessary null assignments in notification.background.spec.ts

* [PM-25682] Ensure linkedId is undefined instead of null

* [PM-25682] Cleanup misc typing errors

* [PM-25682] Make the CipherId required

* [PM-25682] Undo CipherId assertions

* [PM-25682] Undo brand initial value change

* [PM-25682] Update SshKeyView

* [PM-25682] Add constructor to Fido2CredentialView

* [PM-25682] Prettier

* [PM-25682] Fix strict type warnings after merge with main

* [PM-25682] Cleanup cipher view spec

* [PM-25682] Cleanup new type warnings after merge

* [PM-25682] Undo removed eslint-disable-next-line comment

* [PM-25682] Fix flaky test

* [PM-25682] Use satisfies instead of as for Fido2CredentialAutofillView
This commit is contained in:
Shane Melton
2025-10-07 08:40:57 -07:00
committed by GitHub
parent 2127f71f5d
commit 9f0a565241
54 changed files with 424 additions and 503 deletions

View File

@@ -193,7 +193,6 @@ export abstract class BaseImporter {
if (this.isNullOrWhitespace(loginUri.uri)) {
return null;
}
loginUri.match = null;
return [loginUri];
}
@@ -205,7 +204,6 @@ export abstract class BaseImporter {
if (this.isNullOrWhitespace(loginUri.uri)) {
return;
}
loginUri.match = null;
returnArr.push(loginUri);
});
return returnArr.length === 0 ? null : returnArr;
@@ -236,7 +234,7 @@ export abstract class BaseImporter {
return hostname.startsWith("www.") ? hostname.replace("www.", "") : hostname;
}
protected isNullOrWhitespace(str: string): boolean {
protected isNullOrWhitespace(str: string | undefined | null): boolean {
return Utils.isNullOrWhitespace(str);
}

View File

@@ -11,9 +11,6 @@ const CipherData = [
title: "should parse app name",
csv: androidData,
expected: Object.assign(new CipherView(), {
id: null,
organizationId: null,
folderId: null,
name: "com.xyz.example.app.android",
login: Object.assign(new LoginView(), {
username: "username@example.com",
@@ -24,7 +21,6 @@ const CipherData = [
}),
],
}),
notes: null,
type: 1,
}),
},
@@ -32,9 +28,6 @@ const CipherData = [
title: "should parse password",
csv: simplePasswordData,
expected: Object.assign(new CipherView(), {
id: null,
organizationId: null,
folderId: null,
name: "www.example.com",
login: Object.assign(new LoginView(), {
username: "username@example.com",
@@ -45,7 +38,6 @@ const CipherData = [
}),
],
}),
notes: null,
type: 1,
}),
},
@@ -54,6 +46,7 @@ const CipherData = [
describe("Chrome CSV Importer", () => {
CipherData.forEach((data) => {
it(data.title, async () => {
jest.useFakeTimers().setSystemTime(data.expected.creationDate);
const importer = new ChromeCsvImporter();
const result = await importer.parse(data.csv);
expect(result != null).toBe(true);

View File

@@ -59,12 +59,12 @@ describe("Dashlane CSV Importer", () => {
const cipher = result.ciphers.shift();
expect(cipher.type).toBe(CipherType.Card);
expect(cipher.name).toBe("John's savings account");
expect(cipher.card.brand).toBeNull();
expect(cipher.card.brand).toBeUndefined();
expect(cipher.card.cardholderName).toBe("John Doe");
expect(cipher.card.number).toBe("accountNumber");
expect(cipher.card.code).toBeNull();
expect(cipher.card.expMonth).toBeNull();
expect(cipher.card.expYear).toBeNull();
expect(cipher.card.code).toBeUndefined();
expect(cipher.card.expMonth).toBeUndefined();
expect(cipher.card.expYear).toBeUndefined();
expect(cipher.fields.length).toBe(4);
@@ -112,7 +112,7 @@ describe("Dashlane CSV Importer", () => {
expect(cipher.name).toBe("John Doe card");
expect(cipher.identity.fullName).toBe("John Doe");
expect(cipher.identity.firstName).toBe("John");
expect(cipher.identity.middleName).toBeNull();
expect(cipher.identity.middleName).toBeUndefined();
expect(cipher.identity.lastName).toBe("Doe");
expect(cipher.identity.licenseNumber).toBe("123123123");
@@ -133,7 +133,7 @@ describe("Dashlane CSV Importer", () => {
expect(cipher2.name).toBe("John Doe passport");
expect(cipher2.identity.fullName).toBe("John Doe");
expect(cipher2.identity.firstName).toBe("John");
expect(cipher2.identity.middleName).toBeNull();
expect(cipher2.identity.middleName).toBeUndefined();
expect(cipher2.identity.lastName).toBe("Doe");
expect(cipher2.identity.passportNumber).toBe("123123123");
@@ -154,7 +154,7 @@ describe("Dashlane CSV Importer", () => {
expect(cipher3.name).toBe("John Doe license");
expect(cipher3.identity.fullName).toBe("John Doe");
expect(cipher3.identity.firstName).toBe("John");
expect(cipher3.identity.middleName).toBeNull();
expect(cipher3.identity.middleName).toBeUndefined();
expect(cipher3.identity.lastName).toBe("Doe");
expect(cipher3.identity.licenseNumber).toBe("1234556");
expect(cipher3.identity.state).toBe("DC");
@@ -173,7 +173,7 @@ describe("Dashlane CSV Importer", () => {
expect(cipher4.name).toBe("John Doe social_security");
expect(cipher4.identity.fullName).toBe("John Doe");
expect(cipher4.identity.firstName).toBe("John");
expect(cipher4.identity.middleName).toBeNull();
expect(cipher4.identity.middleName).toBeUndefined();
expect(cipher4.identity.lastName).toBe("Doe");
expect(cipher4.identity.ssn).toBe("123123123");

View File

@@ -11,9 +11,6 @@ const CipherData = [
title: "should parse password",
csv: simplePasswordData,
expected: Object.assign(new CipherView(), {
id: null,
organizationId: null,
folderId: null,
name: "example.com",
login: Object.assign(new LoginView(), {
username: "foo",
@@ -24,7 +21,6 @@ const CipherData = [
}),
],
}),
notes: null,
type: 1,
}),
},
@@ -32,9 +28,6 @@ const CipherData = [
title: 'should skip "chrome://FirefoxAccounts"',
csv: firefoxAccountsData,
expected: Object.assign(new CipherView(), {
id: null,
organizationId: null,
folderId: null,
name: "example.com",
login: Object.assign(new LoginView(), {
username: "foo",
@@ -45,7 +38,6 @@ const CipherData = [
}),
],
}),
notes: null,
type: 1,
}),
},
@@ -54,6 +46,7 @@ const CipherData = [
describe("Firefox CSV Importer", () => {
CipherData.forEach((data) => {
it(data.title, async () => {
jest.useFakeTimers().setSystemTime(data.expected.creationDate);
const importer = new FirefoxCsvImporter();
const result = await importer.parse(data.csv);
expect(result != null).toBe(true);

View File

@@ -51,10 +51,10 @@ describe("Keeper CSV Importer", () => {
expect(result != null).toBe(true);
const cipher = result.ciphers.shift();
expect(cipher.login.totp).toBeNull();
expect(cipher.login.totp).toBeUndefined();
const cipher2 = result.ciphers.shift();
expect(cipher2.login.totp).toBeNull();
expect(cipher2.login.totp).toBeUndefined();
const cipher3 = result.ciphers.shift();
expect(cipher3.login.totp).toEqual(

View File

@@ -51,7 +51,7 @@ describe("Keeper Json Importer", () => {
expect(result != null).toBe(true);
const cipher = result.ciphers.shift();
expect(cipher.login.totp).toBeNull();
expect(cipher.login.totp).toBeUndefined();
// 2nd Cipher
const cipher2 = result.ciphers.shift();

View File

@@ -37,9 +37,6 @@ Expiration Date:June,2020
Notes:some text
",Credit-card,,0`,
expected: Object.assign(new CipherView(), {
id: null,
organizationId: null,
folderId: null,
name: "Credit-card",
notes: "some text\n",
type: 3,
@@ -71,11 +68,7 @@ Start Date:,
Expiration Date:,
Notes:",empty,,0`,
expected: Object.assign(new CipherView(), {
id: null,
organizationId: null,
folderId: null,
name: "empty",
notes: null,
type: 3,
card: {
expMonth: undefined,
@@ -101,11 +94,7 @@ Start Date:,
Expiration Date:January,
Notes:",noyear,,0`,
expected: Object.assign(new CipherView(), {
id: null,
organizationId: null,
folderId: null,
name: "noyear",
notes: null,
type: 3,
card: {
cardholderName: "John Doe",
@@ -139,11 +128,7 @@ Start Date:,
Expiration Date:,2020
Notes:",nomonth,,0`,
expected: Object.assign(new CipherView(), {
id: null,
organizationId: null,
folderId: null,
name: "nomonth",
notes: null,
type: 3,
card: {
cardholderName: "John Doe",
@@ -171,6 +156,7 @@ Notes:",nomonth,,0`,
describe("Lastpass CSV Importer", () => {
CipherData.forEach((data) => {
it(data.title, async () => {
jest.useFakeTimers().setSystemTime(data.expected.creationDate);
const importer = new LastPassCsvImporter();
const result = await importer.parse(data.csv);
expect(result != null).toBe(true);

View File

@@ -468,8 +468,8 @@ describe("Myki CSV Importer", () => {
const cipher = result.ciphers.shift();
expect(cipher.name).toEqual("2FA nickname");
expect(cipher.login.username).toBeNull();
expect(cipher.login.password).toBeNull();
expect(cipher.login.username).toBeUndefined();
expect(cipher.login.password).toBeUndefined();
expect(cipher.login.totp).toBe("someTOTPSeed");
expect(cipher.notes).toEqual("Additional information field content.");

View File

@@ -17,8 +17,8 @@ const namesTestData = [
fullName: "MyFirstName",
expected: Object.assign(new IdentityView(), {
firstName: "MyFirstName",
middleName: null,
lastName: null,
middleName: undefined,
lastName: undefined,
}),
},
{
@@ -26,7 +26,7 @@ const namesTestData = [
fullName: "MyFirstName MyLastName",
expected: Object.assign(new IdentityView(), {
firstName: "MyFirstName",
middleName: null,
middleName: undefined,
lastName: "MyLastName",
}),
},

View File

@@ -393,7 +393,7 @@ describe("1Password 1Pux Importer", () => {
const identity = cipher.identity;
expect(identity.firstName).toEqual("Michael");
expect(identity.middleName).toBeNull();
expect(identity.middleName).toBeUndefined();
expect(identity.lastName).toEqual("Scarn");
expect(identity.address1).toEqual("2120 Mifflin Rd.");
expect(identity.state).toEqual("Pennsylvania");
@@ -423,7 +423,7 @@ describe("1Password 1Pux Importer", () => {
const identity = cipher.identity;
expect(identity.firstName).toEqual("Cash");
expect(identity.middleName).toBeNull();
expect(identity.middleName).toBeUndefined();
expect(identity.lastName).toEqual("Bandit");
expect(identity.state).toEqual("Washington");
expect(identity.country).toEqual("United States of America");
@@ -447,7 +447,7 @@ describe("1Password 1Pux Importer", () => {
const identity = cipher.identity;
expect(identity.firstName).toEqual("George");
expect(identity.middleName).toBeNull();
expect(identity.middleName).toBeUndefined();
expect(identity.lastName).toEqual("Engels");
expect(identity.company).toEqual("National Public Library");
expect(identity.phone).toEqual("9995555555");
@@ -472,7 +472,7 @@ describe("1Password 1Pux Importer", () => {
const identity = cipher.identity;
expect(identity.firstName).toEqual("David");
expect(identity.middleName).toBeNull();
expect(identity.middleName).toBeUndefined();
expect(identity.lastName).toEqual("Global");
expect(identity.passportNumber).toEqual("76436847");
@@ -499,7 +499,7 @@ describe("1Password 1Pux Importer", () => {
const identity = cipher.identity;
expect(identity.firstName).toEqual("Chef");
expect(identity.middleName).toBeNull();
expect(identity.middleName).toBeUndefined();
expect(identity.lastName).toEqual("Coldroom");
expect(identity.company).toEqual("Super Cool Store Co.");
@@ -523,7 +523,7 @@ describe("1Password 1Pux Importer", () => {
const identity = cipher.identity;
expect(identity.firstName).toEqual("Jack");
expect(identity.middleName).toBeNull();
expect(identity.middleName).toBeUndefined();
expect(identity.lastName).toEqual("Judd");
expect(identity.ssn).toEqual("131-216-1900");
});
@@ -682,12 +682,12 @@ describe("1Password 1Pux Importer", () => {
expect(folders[3].name).toBe("Education");
expect(folders[4].name).toBe("Starter Kit");
// Check that ciphers have a folder assigned to them
expect(result.ciphers.filter((c) => c.folderId === folders[0].id).length).toBeGreaterThan(0);
expect(result.ciphers.filter((c) => c.folderId === folders[1].id).length).toBeGreaterThan(0);
expect(result.ciphers.filter((c) => c.folderId === folders[2].id).length).toBeGreaterThan(0);
expect(result.ciphers.filter((c) => c.folderId === folders[3].id).length).toBeGreaterThan(0);
expect(result.ciphers.filter((c) => c.folderId === folders[4].id).length).toBeGreaterThan(0);
// Check that folder/cipher relationships
expect(result.folderRelationships.filter(([_, f]) => f == 0).length).toBeGreaterThan(0);
expect(result.folderRelationships.filter(([_, f]) => f == 1).length).toBeGreaterThan(0);
expect(result.folderRelationships.filter(([_, f]) => f == 2).length).toBeGreaterThan(0);
expect(result.folderRelationships.filter(([_, f]) => f == 3).length).toBeGreaterThan(0);
expect(result.folderRelationships.filter(([_, f]) => f == 4).length).toBeGreaterThan(0);
});
it("should create collections if part of an organization", async () => {

View File

@@ -11,9 +11,6 @@ const CipherData = [
title: "should parse URLs in new CSV format",
csv: simplePasswordData,
expected: Object.assign(new CipherView(), {
id: null,
organizationId: null,
folderId: null,
name: "example.com (example_user)",
login: Object.assign(new LoginView(), {
username: "example_user",
@@ -33,9 +30,6 @@ const CipherData = [
title: "should parse URLs in old CSV format",
csv: oldSimplePasswordData,
expected: Object.assign(new CipherView(), {
id: null,
organizationId: null,
folderId: null,
name: "example.com (example_user)",
login: Object.assign(new LoginView(), {
username: "example_user",
@@ -45,6 +39,7 @@ const CipherData = [
uri: "https://example.com",
}),
],
totp: null,
}),
type: 1,
}),
@@ -54,6 +49,7 @@ const CipherData = [
describe("Safari CSV Importer", () => {
CipherData.forEach((data) => {
it(data.title, async () => {
jest.useFakeTimers().setSystemTime(data.expected.creationDate);
const importer = new SafariCsvImporter();
const result = await importer.parse(data.csv);
expect(result != null).toBe(true);

View File

@@ -11,9 +11,6 @@ const CipherData = [
title: "should parse Zoho Vault CSV format",
csv: samplezohovaultcsvdata,
expected: Object.assign(new CipherView(), {
id: null,
organizationId: null,
folderId: null,
name: "XYZ Test",
login: Object.assign(new LoginView(), {
username: "email@domain.de",
@@ -41,6 +38,7 @@ describe("Zoho Vault CSV Importer", () => {
CipherData.forEach((data) => {
it(data.title, async () => {
jest.useFakeTimers().setSystemTime(data.expected.creationDate);
const importer = new ZohoVaultCsvImporter();
const result = await importer.parse(data.csv);
expect(result != null).toBe(true);