Browse Source
* Move existing dashlane importer into dashlaneImporters * Add testData for Dashlane CSV importer * Add dashlane Csv importer and unit tests * Fixed linting issues * Moved dashlaneCsv types to own file * Register DashlaneCsv importer * Removed temp private method and use base impl * rename spec imports * Move scope of mapped columns * Migrate folders into collection if imported via orgPS-589-2fa-device-verification-settings
13 changed files with 749 additions and 11 deletions
@ -0,0 +1,271 @@
@@ -0,0 +1,271 @@
|
||||
import { CipherType } from "../../enums/cipherType"; |
||||
import { SecureNoteType } from "../../enums/secureNoteType"; |
||||
import { ImportResult } from "../../models/domain/importResult"; |
||||
import { CardView } from "../../models/view/cardView"; |
||||
import { CipherView } from "../../models/view/cipherView"; |
||||
import { IdentityView } from "../../models/view/identityView"; |
||||
import { LoginView } from "../../models/view/loginView"; |
||||
import { BaseImporter } from "../baseImporter"; |
||||
import { Importer } from "../importer"; |
||||
|
||||
import { |
||||
CredentialsRecord, |
||||
IdRecord, |
||||
PaymentsRecord, |
||||
PersonalInformationRecord, |
||||
SecureNoteRecord, |
||||
} from "./types/dashlaneCsvTypes"; |
||||
|
||||
const _mappedCredentialsColums = new Set([ |
||||
"title", |
||||
"note", |
||||
"username", |
||||
"password", |
||||
"url", |
||||
"otpSecret", |
||||
"category", |
||||
]); |
||||
|
||||
const _mappedPersonalInfoAsIdentiyColumns = new Set([ |
||||
"type", |
||||
"title", |
||||
"first_name", |
||||
"middle_name", |
||||
"last_name", |
||||
"login", |
||||
"email", |
||||
"phone_number", |
||||
"address", |
||||
"country", |
||||
"state", |
||||
"city", |
||||
"zip", |
||||
// Skip item_name as we already have set a combined name
|
||||
"item_name", |
||||
]); |
||||
|
||||
const _mappedSecureNoteColumns = new Set(["title", "note"]); |
||||
|
||||
export class DashlaneCsvImporter extends BaseImporter implements Importer { |
||||
parse(data: string): Promise<ImportResult> { |
||||
const result = new ImportResult(); |
||||
const results = this.parseCsv(data, true); |
||||
if (results == null) { |
||||
result.success = false; |
||||
return Promise.resolve(result); |
||||
} |
||||
|
||||
if (results[0].type != null && results[0].title != null) { |
||||
const personalRecords = results as PersonalInformationRecord[]; |
||||
|
||||
// If personalRecords has only one "name" then create an Identity-Cipher
|
||||
if (personalRecords.filter((x) => x.type === "name").length === 1) { |
||||
const cipher = this.initLoginCipher(); |
||||
cipher.type = CipherType.Identity; |
||||
cipher.identity = new IdentityView(); |
||||
results.forEach((row) => { |
||||
this.parsePersonalInformationRecordAsIdentity(cipher, row); |
||||
}); |
||||
this.cleanupCipher(cipher); |
||||
result.ciphers.push(cipher); |
||||
result.success = true; |
||||
return Promise.resolve(result); |
||||
} |
||||
} |
||||
|
||||
results.forEach((row) => { |
||||
const cipher = this.initLoginCipher(); |
||||
|
||||
const rowKeys = Object.keys(row); |
||||
if (rowKeys[0] === "username") { |
||||
this.processFolder(result, row.category); |
||||
this.parseCredentialsRecord(cipher, row); |
||||
} |
||||
|
||||
if (rowKeys[0] === "type" && rowKeys[1] === "account_name") { |
||||
this.parsePaymentRecord(cipher, row); |
||||
} |
||||
|
||||
if (rowKeys[0] === "type" && rowKeys[1] === "number") { |
||||
this.parseIdRecord(cipher, row); |
||||
} |
||||
|
||||
if ((rowKeys[0] === "type") != null && rowKeys[1] === "title") { |
||||
this.parsePersonalInformationRecord(cipher, row); |
||||
} |
||||
|
||||
if (rowKeys[0] === "title" && rowKeys[1] === "note") { |
||||
this.parseSecureNoteRecords(cipher, row); |
||||
} |
||||
|
||||
this.convertToNoteIfNeeded(cipher); |
||||
this.cleanupCipher(cipher); |
||||
result.ciphers.push(cipher); |
||||
}); |
||||
|
||||
if (this.organization) { |
||||
this.moveFoldersToCollections(result); |
||||
} |
||||
|
||||
result.success = true; |
||||
return Promise.resolve(result); |
||||
} |
||||
|
||||
parseCredentialsRecord(cipher: CipherView, row: CredentialsRecord) { |
||||
cipher.type = CipherType.Login; |
||||
cipher.login = new LoginView(); |
||||
|
||||
cipher.name = row.title; |
||||
cipher.notes = row.note; |
||||
cipher.login.username = row.username; |
||||
cipher.login.password = row.password; |
||||
cipher.login.totp = row.otpSecret; |
||||
cipher.login.uris = this.makeUriArray(row.url); |
||||
|
||||
this.importUnmappedFields(cipher, row, _mappedCredentialsColums); |
||||
} |
||||
|
||||
parsePaymentRecord(cipher: CipherView, row: PaymentsRecord) { |
||||
cipher.type = CipherType.Card; |
||||
cipher.card = new CardView(); |
||||
|
||||
cipher.name = row.account_name; |
||||
let mappedValues: string[] = []; |
||||
switch (row.type) { |
||||
case "credit_card": |
||||
cipher.card.cardholderName = row.account_name; |
||||
cipher.card.number = row.cc_number; |
||||
cipher.card.brand = this.getCardBrand(cipher.card.number); |
||||
cipher.card.code = row.code; |
||||
cipher.card.expMonth = row.expiration_month; |
||||
cipher.card.expYear = row.expiration_year.substring(2, 4); |
||||
|
||||
// If you add more mapped fields please extend this
|
||||
mappedValues = [ |
||||
"account_name", |
||||
"account_holder", |
||||
"cc_number", |
||||
"code", |
||||
"expiration_month", |
||||
"expiration_year", |
||||
]; |
||||
break; |
||||
case "bank": |
||||
cipher.card.cardholderName = row.account_holder; |
||||
cipher.card.number = row.account_number; |
||||
|
||||
// If you add more mapped fields please extend this
|
||||
mappedValues = ["account_name", "account_holder", "account_number"]; |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
this.importUnmappedFields(cipher, row, new Set(mappedValues)); |
||||
} |
||||
|
||||
parseIdRecord(cipher: CipherView, row: IdRecord) { |
||||
cipher.type = CipherType.Identity; |
||||
cipher.identity = new IdentityView(); |
||||
|
||||
const mappedValues: string[] = ["name", "number"]; |
||||
switch (row.type) { |
||||
case "card": |
||||
cipher.name = `${row.name} ${row.type}`; |
||||
this.processFullName(cipher, row.name); |
||||
cipher.identity.licenseNumber = row.number; |
||||
break; |
||||
case "passport": |
||||
cipher.name = `${row.name} ${row.type}`; |
||||
this.processFullName(cipher, row.name); |
||||
cipher.identity.passportNumber = row.number; |
||||
break; |
||||
case "license": |
||||
cipher.name = `${row.name} ${row.type}`; |
||||
this.processFullName(cipher, row.name); |
||||
cipher.identity.licenseNumber = row.number; |
||||
cipher.identity.state = row.state; |
||||
|
||||
mappedValues.push("state"); |
||||
break; |
||||
case "social_security": |
||||
cipher.name = `${row.name} ${row.type}`; |
||||
this.processFullName(cipher, row.name); |
||||
cipher.identity.ssn = row.number; |
||||
break; |
||||
case "tax_number": |
||||
cipher.name = row.type; |
||||
cipher.identity.licenseNumber = row.number; |
||||
break; |
||||
|
||||
default: |
||||
break; |
||||
} |
||||
|
||||
// If you add more mapped fields please extend this
|
||||
this.importUnmappedFields(cipher, row, new Set(mappedValues)); |
||||
} |
||||
|
||||
parsePersonalInformationRecord(cipher: CipherView, row: PersonalInformationRecord) { |
||||
cipher.type = CipherType.SecureNote; |
||||
cipher.secureNote.type = SecureNoteType.Generic; |
||||
if (row.type === "name") { |
||||
cipher.name = `${row.title} ${row.first_name} ${row.middle_name} ${row.last_name}` |
||||
.replace(" ", " ") |
||||
.trim(); |
||||
} else { |
||||
cipher.name = row.item_name; |
||||
} |
||||
|
||||
const dataRow = row as any; |
||||
Object.keys(row).forEach((key) => { |
||||
this.processKvp(cipher, key, dataRow[key]); |
||||
}); |
||||
} |
||||
|
||||
parsePersonalInformationRecordAsIdentity(cipher: CipherView, row: PersonalInformationRecord) { |
||||
switch (row.type) { |
||||
case "name": |
||||
this.processFullName(cipher, `${row.first_name} ${row.middle_name} ${row.last_name}`); |
||||
cipher.identity.title = row.title; |
||||
cipher.name = cipher.identity.fullName; |
||||
|
||||
cipher.identity.username = row.login; |
||||
break; |
||||
case "email": |
||||
cipher.identity.email = row.email; |
||||
break; |
||||
case "number": |
||||
cipher.identity.phone = row.phone_number; |
||||
break; |
||||
case "address": |
||||
cipher.identity.address1 = row.address; |
||||
cipher.identity.city = row.city; |
||||
cipher.identity.postalCode = row.zip; |
||||
cipher.identity.state = row.state; |
||||
cipher.identity.country = row.country; |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
this.importUnmappedFields(cipher, row, _mappedPersonalInfoAsIdentiyColumns); |
||||
} |
||||
|
||||
parseSecureNoteRecords(cipher: CipherView, row: SecureNoteRecord) { |
||||
cipher.type = CipherType.SecureNote; |
||||
cipher.secureNote.type = SecureNoteType.Generic; |
||||
cipher.name = row.title; |
||||
cipher.notes = row.note; |
||||
|
||||
this.importUnmappedFields(cipher, row, _mappedSecureNoteColumns); |
||||
} |
||||
|
||||
importUnmappedFields(cipher: CipherView, row: any, mappedValues: Set<string>) { |
||||
const unmappedFields = Object.keys(row).filter((x) => !mappedValues.has(x)); |
||||
unmappedFields.forEach((key) => { |
||||
const item = row as any; |
||||
this.processKvp(cipher, key, item[key]); |
||||
}); |
||||
} |
||||
} |
||||
@ -1,13 +1,12 @@
@@ -1,13 +1,12 @@
|
||||
import { CipherType } from "../enums/cipherType"; |
||||
import { SecureNoteType } from "../enums/secureNoteType"; |
||||
import { ImportResult } from "../models/domain/importResult"; |
||||
import { CardView } from "../models/view/cardView"; |
||||
import { CipherView } from "../models/view/cipherView"; |
||||
import { IdentityView } from "../models/view/identityView"; |
||||
import { SecureNoteView } from "../models/view/secureNoteView"; |
||||
|
||||
import { BaseImporter } from "./baseImporter"; |
||||
import { Importer } from "./importer"; |
||||
import { CipherType } from "../../enums/cipherType"; |
||||
import { SecureNoteType } from "../../enums/secureNoteType"; |
||||
import { ImportResult } from "../../models/domain/importResult"; |
||||
import { CardView } from "../../models/view/cardView"; |
||||
import { CipherView } from "../../models/view/cipherView"; |
||||
import { IdentityView } from "../../models/view/identityView"; |
||||
import { SecureNoteView } from "../../models/view/secureNoteView"; |
||||
import { BaseImporter } from "../baseImporter"; |
||||
import { Importer } from "../importer"; |
||||
|
||||
const HandledResults = new Set([ |
||||
"ADDRESS", |
||||
@ -0,0 +1,68 @@
@@ -0,0 +1,68 @@
|
||||
// tslint:disable
|
||||
export class CredentialsRecord { |
||||
username: string; |
||||
username2: string; |
||||
username3: string; |
||||
title: string; |
||||
password: string; |
||||
note: string; |
||||
url: string; |
||||
category: string; |
||||
otpSecret: string; |
||||
} |
||||
|
||||
export class PaymentsRecord { |
||||
type: string; |
||||
account_name: string; |
||||
account_holder: string; |
||||
cc_number: string; |
||||
code: string; |
||||
expiration_month: string; |
||||
expiration_year: string; |
||||
routing_number: string; |
||||
account_number: string; |
||||
country: string; |
||||
issuing_bank: string; |
||||
} |
||||
|
||||
export class IdRecord { |
||||
type: string; |
||||
number: string; |
||||
name: string; |
||||
issue_date: string; |
||||
expiration_date: string; |
||||
place_of_issue: string; |
||||
state: string; |
||||
} |
||||
|
||||
export class PersonalInformationRecord { |
||||
type: string; |
||||
title: string; |
||||
first_name: string; |
||||
middle_name: string; |
||||
last_name: string; |
||||
login: string; |
||||
date_of_birth: string; |
||||
place_of_birth: string; |
||||
email: string; |
||||
email_type: string; |
||||
item_name: string; |
||||
phone_number: string; |
||||
address: string; |
||||
country: string; |
||||
state: string; |
||||
city: string; |
||||
zip: string; |
||||
address_recipient: string; |
||||
address_building: string; |
||||
address_apartment: string; |
||||
address_floor: string; |
||||
address_door_code: string; |
||||
job_title: string; |
||||
url: string; |
||||
} |
||||
|
||||
export class SecureNoteRecord { |
||||
title: string; |
||||
note: string; |
||||
} |
||||
@ -0,0 +1,367 @@
@@ -0,0 +1,367 @@
|
||||
import { CipherType } from "jslib-common/enums/cipherType"; |
||||
import { DashlaneCsvImporter as Importer } from "jslib-common/importers/dashlaneImporters/dashlaneCsvImporter"; |
||||
|
||||
import { credentialsData } from "./testData/dashlaneCsv/credentials.csv"; |
||||
import { identityData } from "./testData/dashlaneCsv/id.csv"; |
||||
import { multiplePersonalInfoData } from "./testData/dashlaneCsv/multiplePersonalInfo.csv"; |
||||
import { paymentsData } from "./testData/dashlaneCsv/payments.csv"; |
||||
import { personalInfoData } from "./testData/dashlaneCsv/personalInfo.csv"; |
||||
import { secureNoteData } from "./testData/dashlaneCsv/securenotes.csv"; |
||||
|
||||
describe("Dashlane CSV Importer", () => { |
||||
let importer: Importer; |
||||
beforeEach(() => { |
||||
importer = new Importer(); |
||||
}); |
||||
|
||||
it("should parse login records", async () => { |
||||
const result = await importer.parse(credentialsData); |
||||
expect(result != null).toBe(true); |
||||
|
||||
const cipher = result.ciphers.shift(); |
||||
expect(cipher.name).toEqual("example.com"); |
||||
expect(cipher.login.username).toEqual("jdoe"); |
||||
expect(cipher.login.password).toEqual("somePassword"); |
||||
expect(cipher.login.totp).toEqual("someTOTPSeed"); |
||||
expect(cipher.login.uris.length).toEqual(1); |
||||
const uriView = cipher.login.uris.shift(); |
||||
expect(uriView.uri).toEqual("https://www.example.com"); |
||||
expect(cipher.notes).toEqual("some note for example.com"); |
||||
}); |
||||
|
||||
it("should parse an item and create a folder", async () => { |
||||
const result = await importer.parse(credentialsData); |
||||
|
||||
expect(result).not.toBeNull(); |
||||
expect(result.success).toBe(true); |
||||
expect(result.folders.length).toBe(1); |
||||
expect(result.folders[0].name).toBe("Entertainment"); |
||||
expect(result.folderRelationships[0]).toEqual([0, 0]); |
||||
}); |
||||
|
||||
it("should parse payment records", async () => { |
||||
const result = await importer.parse(paymentsData); |
||||
|
||||
expect(result).not.toBeNull(); |
||||
expect(result.success).toBe(true); |
||||
expect(result.ciphers.length).toBe(2); |
||||
|
||||
// Account
|
||||
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.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.fields.length).toBe(4); |
||||
|
||||
expect(cipher.fields[0].name).toBe("type"); |
||||
expect(cipher.fields[0].value).toBe("bank"); |
||||
|
||||
expect(cipher.fields[1].name).toBe("routing_number"); |
||||
expect(cipher.fields[1].value).toBe("routingNumber"); |
||||
|
||||
expect(cipher.fields[2].name).toBe("country"); |
||||
expect(cipher.fields[2].value).toBe("US"); |
||||
|
||||
expect(cipher.fields[3].name).toBe("issuing_bank"); |
||||
expect(cipher.fields[3].value).toBe("US-ALLY"); |
||||
|
||||
// CreditCard
|
||||
const cipher2 = result.ciphers.shift(); |
||||
expect(cipher2.type).toBe(CipherType.Card); |
||||
expect(cipher2.name).toBe("John Doe"); |
||||
expect(cipher2.card.brand).toBe("Visa"); |
||||
expect(cipher2.card.cardholderName).toBe("John Doe"); |
||||
expect(cipher2.card.number).toBe("41111111111111111"); |
||||
expect(cipher2.card.code).toBe("123"); |
||||
expect(cipher2.card.expMonth).toBe("01"); |
||||
expect(cipher2.card.expYear).toBe("23"); |
||||
|
||||
expect(cipher2.fields.length).toBe(2); |
||||
|
||||
expect(cipher2.fields[0].name).toBe("type"); |
||||
expect(cipher2.fields[0].value).toBe("credit_card"); |
||||
|
||||
expect(cipher2.fields[1].name).toBe("country"); |
||||
expect(cipher2.fields[1].value).toBe("US"); |
||||
}); |
||||
|
||||
it("should parse ids records", async () => { |
||||
const result = await importer.parse(identityData); |
||||
|
||||
expect(result).not.toBeNull(); |
||||
expect(result.success).toBe(true); |
||||
|
||||
// Type card
|
||||
const cipher = result.ciphers.shift(); |
||||
expect(cipher.type).toBe(CipherType.Identity); |
||||
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.lastName).toBe("Doe"); |
||||
expect(cipher.identity.licenseNumber).toBe("123123123"); |
||||
|
||||
expect(cipher.fields.length).toBe(3); |
||||
|
||||
expect(cipher.fields[0].name).toEqual("type"); |
||||
expect(cipher.fields[0].value).toEqual("card"); |
||||
|
||||
expect(cipher.fields[1].name).toEqual("issue_date"); |
||||
expect(cipher.fields[1].value).toEqual("2022-1-30"); |
||||
|
||||
expect(cipher.fields[2].name).toEqual("expiration_date"); |
||||
expect(cipher.fields[2].value).toEqual("2032-1-30"); |
||||
|
||||
// Type passport
|
||||
const cipher2 = result.ciphers.shift(); |
||||
expect(cipher2.type).toBe(CipherType.Identity); |
||||
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.lastName).toBe("Doe"); |
||||
expect(cipher2.identity.passportNumber).toBe("123123123"); |
||||
|
||||
expect(cipher2.fields.length).toBe(4); |
||||
|
||||
expect(cipher2.fields[0].name).toEqual("type"); |
||||
expect(cipher2.fields[0].value).toEqual("passport"); |
||||
expect(cipher2.fields[1].name).toEqual("issue_date"); |
||||
expect(cipher2.fields[1].value).toEqual("2022-1-30"); |
||||
expect(cipher2.fields[2].name).toEqual("expiration_date"); |
||||
expect(cipher2.fields[2].value).toEqual("2032-1-30"); |
||||
expect(cipher2.fields[3].name).toEqual("place_of_issue"); |
||||
expect(cipher2.fields[3].value).toEqual("somewhere in Germany"); |
||||
|
||||
// Type license
|
||||
const cipher3 = result.ciphers.shift(); |
||||
expect(cipher3.type).toBe(CipherType.Identity); |
||||
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.lastName).toBe("Doe"); |
||||
expect(cipher3.identity.licenseNumber).toBe("1234556"); |
||||
expect(cipher3.identity.state).toBe("DC"); |
||||
|
||||
expect(cipher3.fields.length).toBe(3); |
||||
expect(cipher3.fields[0].name).toEqual("type"); |
||||
expect(cipher3.fields[0].value).toEqual("license"); |
||||
expect(cipher3.fields[1].name).toEqual("issue_date"); |
||||
expect(cipher3.fields[1].value).toEqual("2022-8-10"); |
||||
expect(cipher3.fields[2].name).toEqual("expiration_date"); |
||||
expect(cipher3.fields[2].value).toEqual("2022-10-10"); |
||||
|
||||
// Type social_security
|
||||
const cipher4 = result.ciphers.shift(); |
||||
expect(cipher4.type).toBe(CipherType.Identity); |
||||
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.lastName).toBe("Doe"); |
||||
expect(cipher4.identity.ssn).toBe("123123123"); |
||||
|
||||
expect(cipher4.fields.length).toBe(1); |
||||
expect(cipher4.fields[0].name).toEqual("type"); |
||||
expect(cipher4.fields[0].value).toEqual("social_security"); |
||||
|
||||
// Type tax_number
|
||||
const cipher5 = result.ciphers.shift(); |
||||
expect(cipher5.type).toBe(CipherType.Identity); |
||||
expect(cipher5.name).toBe("tax_number"); |
||||
expect(cipher5.identity.licenseNumber).toBe("123123123"); |
||||
|
||||
expect(cipher5.fields.length).toBe(1); |
||||
expect(cipher5.fields[0].name).toEqual("type"); |
||||
expect(cipher5.fields[0].value).toEqual("tax_number"); |
||||
}); |
||||
|
||||
it("should parse secureNote records", async () => { |
||||
const result = await importer.parse(secureNoteData); |
||||
|
||||
expect(result).not.toBeNull(); |
||||
expect(result.success).toBe(true); |
||||
expect(result.ciphers.length).toBe(1); |
||||
|
||||
const cipher = result.ciphers.shift(); |
||||
expect(cipher.type).toBe(CipherType.SecureNote); |
||||
expect(cipher.name).toBe("01"); |
||||
expect(cipher.notes).toBe("test"); |
||||
}); |
||||
|
||||
it("should parse personal information records (multiple identities)", async () => { |
||||
const result = await importer.parse(multiplePersonalInfoData); |
||||
|
||||
expect(result).not.toBeNull(); |
||||
expect(result.success).toBe(true); |
||||
expect(result.ciphers.length).toBe(6); |
||||
|
||||
// name
|
||||
const cipher = result.ciphers.shift(); |
||||
expect(cipher.type).toBe(CipherType.SecureNote); |
||||
expect(cipher.name).toBe("MR John Doe"); |
||||
|
||||
expect(cipher.fields.length).toBe(7); |
||||
expect(cipher.fields[0].name).toEqual("type"); |
||||
expect(cipher.fields[0].value).toEqual("name"); |
||||
expect(cipher.fields[1].name).toEqual("title"); |
||||
expect(cipher.fields[1].value).toEqual("MR"); |
||||
expect(cipher.fields[2].name).toEqual("first_name"); |
||||
expect(cipher.fields[2].value).toEqual("John"); |
||||
expect(cipher.fields[3].name).toEqual("last_name"); |
||||
expect(cipher.fields[3].value).toEqual("Doe"); |
||||
expect(cipher.fields[4].name).toEqual("login"); |
||||
expect(cipher.fields[4].value).toEqual("jdoe"); |
||||
expect(cipher.fields[5].name).toEqual("date_of_birth"); |
||||
expect(cipher.fields[5].value).toEqual("2022-01-30"); |
||||
expect(cipher.fields[6].name).toEqual("place_of_birth"); |
||||
expect(cipher.fields[6].value).toEqual("world"); |
||||
|
||||
// email
|
||||
const cipher2 = result.ciphers.shift(); |
||||
expect(cipher2.type).toBe(CipherType.SecureNote); |
||||
expect(cipher2.name).toBe("Johns email"); |
||||
|
||||
expect(cipher2.fields.length).toBe(4); |
||||
expect(cipher2.fields[0].name).toEqual("type"); |
||||
expect(cipher2.fields[0].value).toEqual("email"); |
||||
expect(cipher2.fields[1].name).toEqual("email"); |
||||
expect(cipher2.fields[1].value).toEqual("jdoe@example.com"); |
||||
expect(cipher2.fields[2].name).toEqual("email_type"); |
||||
expect(cipher2.fields[2].value).toEqual("personal"); |
||||
expect(cipher2.fields[3].name).toEqual("item_name"); |
||||
expect(cipher2.fields[3].value).toEqual("Johns email"); |
||||
|
||||
// number
|
||||
const cipher3 = result.ciphers.shift(); |
||||
expect(cipher3.type).toBe(CipherType.SecureNote); |
||||
expect(cipher3.name).toBe("John's number"); |
||||
|
||||
expect(cipher3.fields.length).toBe(3); |
||||
expect(cipher3.fields[0].name).toEqual("type"); |
||||
expect(cipher3.fields[0].value).toEqual("number"); |
||||
expect(cipher3.fields[1].name).toEqual("item_name"); |
||||
expect(cipher3.fields[1].value).toEqual("John's number"); |
||||
expect(cipher3.fields[2].name).toEqual("phone_number"); |
||||
expect(cipher3.fields[2].value).toEqual("+49123123123"); |
||||
|
||||
// address
|
||||
const cipher4 = result.ciphers.shift(); |
||||
expect(cipher4.type).toBe(CipherType.SecureNote); |
||||
expect(cipher4.name).toBe("John's home address"); |
||||
|
||||
expect(cipher4.fields.length).toBe(12); |
||||
expect(cipher4.fields[0].name).toEqual("type"); |
||||
expect(cipher4.fields[0].value).toEqual("address"); |
||||
expect(cipher4.fields[1].name).toEqual("item_name"); |
||||
expect(cipher4.fields[1].value).toEqual("John's home address"); |
||||
expect(cipher4.fields[2].name).toEqual("address"); |
||||
expect(cipher4.fields[2].value).toEqual("1 some street"); |
||||
expect(cipher4.fields[3].name).toEqual("country"); |
||||
expect(cipher4.fields[3].value).toEqual("de"); |
||||
expect(cipher4.fields[4].name).toEqual("state"); |
||||
expect(cipher4.fields[4].value).toEqual("DE-0-NW"); |
||||
expect(cipher4.fields[5].name).toEqual("city"); |
||||
expect(cipher4.fields[5].value).toEqual("some city"); |
||||
expect(cipher4.fields[6].name).toEqual("zip"); |
||||
expect(cipher4.fields[6].value).toEqual("123123"); |
||||
expect(cipher4.fields[7].name).toEqual("address_recipient"); |
||||
expect(cipher4.fields[7].value).toEqual("John"); |
||||
expect(cipher4.fields[8].name).toEqual("address_building"); |
||||
expect(cipher4.fields[8].value).toEqual("1"); |
||||
expect(cipher4.fields[9].name).toEqual("address_apartment"); |
||||
expect(cipher4.fields[9].value).toEqual("1"); |
||||
expect(cipher4.fields[10].name).toEqual("address_floor"); |
||||
expect(cipher4.fields[10].value).toEqual("1"); |
||||
expect(cipher4.fields[11].name).toEqual("address_door_code"); |
||||
expect(cipher4.fields[11].value).toEqual("123"); |
||||
|
||||
// website
|
||||
const cipher5 = result.ciphers.shift(); |
||||
expect(cipher5.type).toBe(CipherType.SecureNote); |
||||
expect(cipher5.name).toBe("Website"); |
||||
|
||||
expect(cipher5.fields.length).toBe(3); |
||||
expect(cipher5.fields[0].name).toEqual("type"); |
||||
expect(cipher5.fields[0].value).toEqual("website"); |
||||
expect(cipher5.fields[1].name).toEqual("item_name"); |
||||
expect(cipher5.fields[1].value).toEqual("Website"); |
||||
expect(cipher5.fields[2].name).toEqual("url"); |
||||
expect(cipher5.fields[2].value).toEqual("website.com"); |
||||
|
||||
// 2nd name/identity
|
||||
const cipher6 = result.ciphers.shift(); |
||||
expect(cipher6.type).toBe(CipherType.SecureNote); |
||||
expect(cipher6.name).toBe("Mrs Jane Doe"); |
||||
|
||||
expect(cipher6.fields.length).toBe(7); |
||||
expect(cipher6.fields[0].name).toEqual("type"); |
||||
expect(cipher6.fields[0].value).toEqual("name"); |
||||
expect(cipher6.fields[1].name).toEqual("title"); |
||||
expect(cipher6.fields[1].value).toEqual("Mrs"); |
||||
expect(cipher6.fields[2].name).toEqual("first_name"); |
||||
expect(cipher6.fields[2].value).toEqual("Jane"); |
||||
expect(cipher6.fields[3].name).toEqual("last_name"); |
||||
expect(cipher6.fields[3].value).toEqual("Doe"); |
||||
expect(cipher6.fields[4].name).toEqual("login"); |
||||
expect(cipher6.fields[4].value).toEqual("jdoe"); |
||||
expect(cipher6.fields[5].name).toEqual("date_of_birth"); |
||||
expect(cipher6.fields[5].value).toEqual("2022-01-30"); |
||||
expect(cipher6.fields[6].name).toEqual("place_of_birth"); |
||||
expect(cipher6.fields[6].value).toEqual("earth"); |
||||
}); |
||||
|
||||
it("should combine personal information records to one identity if only one identity present", async () => { |
||||
const result = await importer.parse(personalInfoData); |
||||
|
||||
expect(result).not.toBeNull(); |
||||
expect(result.success).toBe(true); |
||||
|
||||
const cipher = result.ciphers.shift(); |
||||
expect(cipher.type).toBe(CipherType.Identity); |
||||
expect(cipher.name).toBe("MR John Doe"); |
||||
expect(cipher.identity.fullName).toBe("MR John Doe"); |
||||
expect(cipher.identity.title).toBe("MR"); |
||||
expect(cipher.identity.firstName).toBe("John"); |
||||
expect(cipher.identity.middleName).toBeNull(); |
||||
expect(cipher.identity.lastName).toBe("Doe"); |
||||
expect(cipher.identity.username).toBe("jdoe"); |
||||
expect(cipher.identity.email).toBe("jdoe@example.com"); |
||||
expect(cipher.identity.phone).toBe("+49123123123"); |
||||
|
||||
expect(cipher.fields.length).toBe(9); |
||||
expect(cipher.fields[0].name).toBe("date_of_birth"); |
||||
expect(cipher.fields[0].value).toBe("2022-01-30"); |
||||
|
||||
expect(cipher.fields[1].name).toBe("place_of_birth"); |
||||
expect(cipher.fields[1].value).toBe("world"); |
||||
|
||||
expect(cipher.fields[2].name).toBe("email_type"); |
||||
expect(cipher.fields[2].value).toBe("personal"); |
||||
|
||||
expect(cipher.fields[3].name).toBe("address_recipient"); |
||||
expect(cipher.fields[3].value).toBe("John"); |
||||
|
||||
expect(cipher.fields[4].name).toBe("address_building"); |
||||
expect(cipher.fields[4].value).toBe("1"); |
||||
|
||||
expect(cipher.fields[5].name).toBe("address_apartment"); |
||||
expect(cipher.fields[5].value).toBe("1"); |
||||
|
||||
expect(cipher.fields[6].name).toBe("address_floor"); |
||||
expect(cipher.fields[6].value).toBe("1"); |
||||
|
||||
expect(cipher.fields[7].name).toBe("address_door_code"); |
||||
expect(cipher.fields[7].value).toBe("123"); |
||||
|
||||
expect(cipher.fields[8].name).toBe("url"); |
||||
expect(cipher.fields[8].value).toBe("website.com"); |
||||
}); |
||||
}); |
||||
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
export const credentialsData = `username,username2,username3,title,password,note,url,category,otpSecret
|
||||
jdoe,,,example.com,somePassword,some note for example.com,https://www.example.com,Entertainment,someTOTPSeed`;
|
||||
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
export const identityData = `type,number,name,issue_date,expiration_date,place_of_issue,state
|
||||
card,123123123,John Doe,2022-1-30,2032-1-30,, |
||||
passport,123123123,John Doe,2022-1-30,2032-1-30,somewhere in Germany, |
||||
license,1234556,John Doe,2022-8-10,2022-10-10,,DC |
||||
social_security,123123123,John Doe,,,, |
||||
tax_number,123123123,,,,,`;
|
||||
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
export const multiplePersonalInfoData = `type,title,first_name,middle_name,last_name,login,date_of_birth,place_of_birth,email,email_type,item_name,phone_number,address,country,state,city,zip,address_recipient,address_building,address_apartment,address_floor,address_door_code,job_title,url
|
||||
name,MR,John,,Doe,jdoe,2022-01-30,world,,,,,,,,,,,,,,,, |
||||
email,,,,,,,,jdoe@example.com,personal,Johns email,,,,,,,,,,,,, |
||||
number,,,,,,,,,,John's number,+49123123123,,,,,,,,,,,, |
||||
address,,,,,,,,,,John's home address,,1 some street,de,DE-0-NW,some city,123123,John,1,1,1,123,, |
||||
website,,,,,,,,,,Website,,,,,,,,,,,,,website.com |
||||
name,Mrs,Jane,,Doe,jdoe,2022-01-30,earth,,,,,,,,,,,,,,,,`;
|
||||
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
export const paymentsData = `type,account_name,account_holder,cc_number,code,expiration_month,expiration_year,routing_number,account_number,country,issuing_bank
|
||||
bank,John's savings account,John Doe,,,,,routingNumber,accountNumber,US,US-ALLY |
||||
credit_card,John Doe,,41111111111111111,123,01,2023,,,US,`;
|
||||
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
export const personalInfoData = `type,title,first_name,middle_name,last_name,login,date_of_birth,place_of_birth,email,email_type,item_name,phone_number,address,country,state,city,zip,address_recipient,address_building,address_apartment,address_floor,address_door_code,job_title,url
|
||||
name,MR,John,,Doe,jdoe,2022-01-30,world,,,,,,,,,,,,,,,, |
||||
email,,,,,,,,jdoe@example.com,personal,Johns email,,,,,,,,,,,,, |
||||
number,,,,,,,,,,John's number,+49123123123,,,,,,,,,,,, |
||||
address,,,,,,,,,,John's home address,,1 some street,de,DE-0-NW,some city,123123,John,1,1,1,123,, |
||||
website,,,,,,,,,,Website,,,,,,,,,,,,,website.com`;
|
||||
Loading…
Reference in new issue