1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-22 11:45:59 +01:00

[EC-142] Fix error during import of 1pux containing new email field format (#758)

* Add support for complex email field type

* Ensure complex email field type gets imported on identities
This commit is contained in:
Daniel James Smith 2022-04-06 17:33:43 +02:00 committed by GitHub
parent 5f4a8c18fe
commit 3b9ef68f4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 405 additions and 13 deletions

View File

@ -11,6 +11,9 @@ import { CreditCardData } from "./testData/onePassword1Pux/CreditCard";
import { DatabaseData } from "./testData/onePassword1Pux/Database";
import { DriversLicenseData } from "./testData/onePassword1Pux/DriversLicense";
import { EmailAccountData } from "./testData/onePassword1Pux/EmailAccount";
import { EmailFieldData } from "./testData/onePassword1Pux/Emailfield";
import { EmailFieldOnIdentityData } from "./testData/onePassword1Pux/EmailfieldOnIdentity";
import { EmailFieldOnIdentityPrefilledData } from "./testData/onePassword1Pux/EmailfieldOnIdentity_Prefilled";
import { IdentityData } from "./testData/onePassword1Pux/IdentityData";
import { LoginData } from "./testData/onePassword1Pux/LoginData";
import { MedicalRecordData } from "./testData/onePassword1Pux/MedicalRecord";
@ -102,6 +105,25 @@ describe("1Password 1Pux Importer", () => {
expect(cipher.fields[1].type).toBe(FieldType.Boolean);
});
it("should add fields of type email as custom fields", async () => {
const importer = new Importer();
const EmailFieldDataJson = JSON.stringify(EmailFieldData);
const result = await importer.parse(EmailFieldDataJson);
expect(result != null).toBe(true);
const ciphers = result.ciphers;
expect(ciphers.length).toEqual(1);
const cipher = ciphers.shift();
expect(cipher.fields[0].name).toEqual("reg_email");
expect(cipher.fields[0].value).toEqual("kriddler@nullvalue.test");
expect(cipher.fields[0].type).toBe(FieldType.Text);
expect(cipher.fields[1].name).toEqual("provider");
expect(cipher.fields[1].value).toEqual("myEmailProvider");
expect(cipher.fields[1].type).toBe(FieldType.Text);
});
it('should create concealed field as "hidden" type', async () => {
const importer = new Importer();
const result = await importer.parse(OnePuxExampleFileJson);
@ -205,6 +227,46 @@ describe("1Password 1Pux Importer", () => {
validateCustomField(cipher.fields, "forumsig", "super cool guy");
});
it("emails fields on identity types should be added to the identity email field", async () => {
const importer = new Importer();
const EmailFieldOnIdentityDataJson = JSON.stringify(EmailFieldOnIdentityData);
const result = await importer.parse(EmailFieldOnIdentityDataJson);
expect(result != null).toBe(true);
const ciphers = result.ciphers;
expect(ciphers.length).toEqual(1);
const cipher = ciphers.shift();
const identity = cipher.identity;
expect(identity.email).toEqual("gengels@nullvalue.test");
expect(cipher.fields[0].name).toEqual("provider");
expect(cipher.fields[0].value).toEqual("myEmailProvider");
expect(cipher.fields[0].type).toBe(FieldType.Text);
});
it("emails fields on identity types should be added to custom fields if identity.email has been filled", async () => {
const importer = new Importer();
const EmailFieldOnIdentityPrefilledDataJson = JSON.stringify(EmailFieldOnIdentityPrefilledData);
const result = await importer.parse(EmailFieldOnIdentityPrefilledDataJson);
expect(result != null).toBe(true);
const ciphers = result.ciphers;
expect(ciphers.length).toEqual(1);
const cipher = ciphers.shift();
const identity = cipher.identity;
expect(identity.email).toEqual("gengels@nullvalue.test");
expect(cipher.fields[0].name).toEqual("2nd_email");
expect(cipher.fields[0].value).toEqual("kriddler@nullvalue.test");
expect(cipher.fields[0].type).toBe(FieldType.Text);
expect(cipher.fields[1].name).toEqual("provider");
expect(cipher.fields[1].value).toEqual("myEmailProvider");
expect(cipher.fields[1].type).toBe(FieldType.Text);
});
it("should parse category 005 - Password (Legacy)", async () => {
const importer = new Importer();
const jsonString = JSON.stringify(PasswordData);

View File

@ -0,0 +1,91 @@
import { ExportData } from "jslib-common/importers/onepasswordImporters/types/onepassword1PuxImporterTypes";
export const EmailFieldData: ExportData = {
accounts: [
{
attrs: {
accountName: "1Password Customer",
name: "1Password Customer",
avatar: "",
email: "username123123123@gmail.com",
uuid: "TRIZ3XV4JJFRXJ3BARILLTUA6E",
domain: "https://my.1password.com/",
},
vaults: [
{
attrs: {
uuid: "pqcgbqjxr4tng2hsqt5ffrgwju",
desc: "Just test entries",
avatar: "ke7i5rxnjrh3tj6uesstcosspu.png",
name: "T's Test Vault",
type: "U",
},
items: [
{
uuid: "47hvppiuwbanbza7bq6jpdjfxu",
favIndex: 1,
createdAt: 1619467985,
updatedAt: 1619468230,
trashed: false,
categoryUuid: "100",
details: {
loginFields: [],
notesPlain: "My Software License",
sections: [
{
title: "",
fields: [],
},
{
title: "Customer",
name: "customer",
fields: [
{
title: "registered email",
id: "reg_email",
value: {
email: {
email_address: "kriddler@nullvalue.test",
provider: "myEmailProvider",
},
},
indexAtSource: 1,
guarded: false,
multiline: false,
dontGenerate: false,
inputTraits: {
keyboard: "emailAddress",
correction: "default",
capitalization: "default",
},
},
],
},
{
title: "Publisher",
name: "publisher",
fields: [],
},
{
title: "Order",
name: "order",
fields: [],
},
],
passwordHistory: [],
},
overview: {
subtitle: "5.10.1000",
title: "Limux Product Key",
url: "",
ps: 0,
pbe: 0.0,
pgrng: false,
},
},
],
},
],
},
],
};

View File

@ -0,0 +1,87 @@
import { ExportData } from "jslib-common/importers/onepasswordImporters/types/onepassword1PuxImporterTypes";
export const EmailFieldOnIdentityData: ExportData = {
accounts: [
{
attrs: {
accountName: "1Password Customer",
name: "1Password Customer",
avatar: "",
email: "username123123123@gmail.com",
uuid: "TRIZ3XV4JJFRXJ3BARILLTUA6E",
domain: "https://my.1password.com/",
},
vaults: [
{
attrs: {
uuid: "pqcgbqjxr4tng2hsqt5ffrgwju",
desc: "Just test entries",
avatar: "ke7i5rxnjrh3tj6uesstcosspu.png",
name: "T's Test Vault",
type: "U",
},
items: [
{
uuid: "45mjttbbq3owgij2uis55pfrlq",
favIndex: 0,
createdAt: 1619465450,
updatedAt: 1619465789,
trashed: false,
categoryUuid: "004",
details: {
loginFields: [],
notesPlain: "",
sections: [
{
title: "Identification",
name: "name",
fields: [],
},
{
title: "Address",
name: "address",
fields: [],
},
{
title: "Internet Details",
name: "internet",
fields: [
{
title: "E-mail",
id: "E-mail",
value: {
email: {
email_address: "gengels@nullvalue.test",
provider: "myEmailProvider",
},
},
indexAtSource: 4,
guarded: false,
multiline: false,
dontGenerate: false,
inputTraits: {
keyboard: "emailAddress",
correction: "default",
capitalization: "default",
},
},
],
},
],
passwordHistory: [],
},
overview: {
subtitle: "George Engels",
title: "George Engels",
url: "",
ps: 0,
pbe: 0.0,
pgrng: false,
},
},
],
},
],
},
],
};

View File

@ -0,0 +1,103 @@
import { ExportData } from "jslib-common/importers/onepasswordImporters/types/onepassword1PuxImporterTypes";
export const EmailFieldOnIdentityPrefilledData: ExportData = {
accounts: [
{
attrs: {
accountName: "1Password Customer",
name: "1Password Customer",
avatar: "",
email: "username123123123@gmail.com",
uuid: "TRIZ3XV4JJFRXJ3BARILLTUA6E",
domain: "https://my.1password.com/",
},
vaults: [
{
attrs: {
uuid: "pqcgbqjxr4tng2hsqt5ffrgwju",
desc: "Just test entries",
avatar: "ke7i5rxnjrh3tj6uesstcosspu.png",
name: "T's Test Vault",
type: "U",
},
items: [
{
uuid: "45mjttbbq3owgij2uis55pfrlq",
favIndex: 0,
createdAt: 1619465450,
updatedAt: 1619465789,
trashed: false,
categoryUuid: "004",
details: {
loginFields: [],
notesPlain: "",
sections: [
{
title: "Identification",
name: "name",
fields: [],
},
{
title: "Address",
name: "address",
fields: [],
},
{
title: "Internet Details",
name: "internet",
fields: [
{
title: "email",
id: "email",
value: {
string: "gengels@nullvalue.test",
},
indexAtSource: 4,
guarded: false,
multiline: false,
dontGenerate: false,
inputTraits: {
keyboard: "emailAddress",
correction: "default",
capitalization: "default",
},
},
{
title: "2nd email",
id: "2nd_email",
value: {
email: {
email_address: "kriddler@nullvalue.test",
provider: "myEmailProvider",
},
},
indexAtSource: 1,
guarded: false,
multiline: false,
dontGenerate: false,
inputTraits: {
keyboard: "emailAddress",
correction: "default",
capitalization: "default",
},
},
],
},
],
passwordHistory: [],
},
overview: {
subtitle: "George Engels",
title: "George Engels",
url: "",
ps: 0,
pbe: 0.0,
pgrng: false,
},
},
],
},
],
},
],
};

View File

@ -344,7 +344,10 @@ export const SanitizedExport: ExportData = {
title: "",
id: "irpvnshg5kjpkmj5jwy4xxkfom",
value: {
email: "plexuser@nullvalue.test",
email: {
email_address: "plexuser@nullvalue.test",
provider: null,
},
},
indexAtSource: 0,
guarded: false,
@ -1434,7 +1437,10 @@ export const SanitizedExport: ExportData = {
title: "registered email",
id: "reg_email",
value: {
email: "kriddler@nullvalue.test",
email: {
email_address: "kriddler@nullvalue.test",
provider: null,
},
},
indexAtSource: 1,
guarded: false,
@ -1536,7 +1542,10 @@ export const SanitizedExport: ExportData = {
title: "support email",
id: "support_email",
value: {
email: "support@nullvalue.test",
email: {
email_address: "support@nullvalue.test",
provider: null,
},
},
indexAtSource: 4,
guarded: false,
@ -4014,7 +4023,10 @@ export const SanitizedExport: ExportData = {
title: "registered email",
id: "reg_email",
value: {
email: "",
email: {
email_address: "",
provider: null,
},
},
indexAtSource: 1,
guarded: false,
@ -4116,7 +4128,10 @@ export const SanitizedExport: ExportData = {
title: "support email",
id: "support_email",
value: {
email: "",
email: {
email_address: "",
provider: null,
},
},
indexAtSource: 4,
guarded: false,

View File

@ -93,7 +93,10 @@ export const SoftwareLicenseData: ExportData = {
title: "registered email",
id: "reg_email",
value: {
email: "kriddler@nullvalue.test",
email: {
email_address: "kriddler@nullvalue.test",
provider: null,
},
},
indexAtSource: 1,
guarded: false,
@ -195,7 +198,10 @@ export const SoftwareLicenseData: ExportData = {
title: "support email",
id: "support_email",
value: {
email: "support@nullvalue.test",
email: {
email_address: "support@nullvalue.test",
provider: null,
},
},
indexAtSource: 4,
guarded: false,

View File

@ -258,7 +258,7 @@ export class OnePassword1PuxImporter extends BaseImporter implements Importer {
}
}
} else if (cipher.type === CipherType.Identity) {
if (this.fillIdentity(field, fieldValue, cipher)) {
if (this.fillIdentity(field, fieldValue, cipher, valueKey)) {
return;
}
if (valueKey === "address") {
@ -312,6 +312,14 @@ export class OnePassword1PuxImporter extends BaseImporter implements Importer {
}
}
if (valueKey === "email") {
// fieldValue is an object casted into a string, so access the plain value instead
const { email_address, provider } = field.value.email;
this.processKvp(cipher, fieldName, email_address, FieldType.Text);
this.processKvp(cipher, "provider", provider, FieldType.Text);
return;
}
// Do not include a password field if it's already in the history
if (
field.title === "password" &&
@ -440,7 +448,12 @@ export class OnePassword1PuxImporter extends BaseImporter implements Importer {
return false;
}
private fillIdentity(field: FieldsEntity, fieldValue: string, cipher: CipherView): boolean {
private fillIdentity(
field: FieldsEntity,
fieldValue: string,
cipher: CipherView,
valueKey: string
): boolean {
if (this.isNullOrWhitespace(cipher.identity.firstName) && field.id === "firstname") {
cipher.identity.firstName = fieldValue;
return true;
@ -466,9 +479,18 @@ export class OnePassword1PuxImporter extends BaseImporter implements Importer {
return true;
}
if (this.isNullOrWhitespace(cipher.identity.email) && field.id === "email") {
cipher.identity.email = fieldValue;
return true;
if (this.isNullOrWhitespace(cipher.identity.email)) {
if (valueKey === "email") {
const { email_address, provider } = field.value.email;
cipher.identity.email = this.getValueOrDefault(email_address);
this.processKvp(cipher, "provider", provider, FieldType.Text);
return true;
}
if (field.id === "email") {
cipher.identity.email = fieldValue;
return true;
}
}
if (this.isNullOrWhitespace(cipher.identity.username) && field.id === "username") {

View File

@ -106,7 +106,7 @@ export interface Value {
date?: number | null;
string?: string | null;
concealed?: string | null;
email?: string | null;
email?: Email | null;
phone?: string | null;
menu?: string | null;
gender?: string | null;
@ -117,6 +117,12 @@ export interface Value {
creditCardNumber?: string | null;
reference?: string | null;
}
export interface Email {
email_address: string;
provider: string;
}
export interface Address {
street: string;
city: string;