From ed74f73a8ca2d26cacf2f74b4cd14c6150711b87 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Wed, 12 Dec 2018 17:06:13 -0500 Subject: [PATCH] dashlane json importer --- src/importers/dashlaneCsvImporter.ts | 90 -------------- src/importers/dashlaneJsonImporter.ts | 164 ++++++++++++++++++++++++++ src/services/import.service.ts | 8 +- 3 files changed, 168 insertions(+), 94 deletions(-) delete mode 100644 src/importers/dashlaneCsvImporter.ts create mode 100644 src/importers/dashlaneJsonImporter.ts diff --git a/src/importers/dashlaneCsvImporter.ts b/src/importers/dashlaneCsvImporter.ts deleted file mode 100644 index 028a79a055..0000000000 --- a/src/importers/dashlaneCsvImporter.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { BaseImporter } from './baseImporter'; -import { Importer } from './importer'; - -import { ImportResult } from '../models/domain/importResult'; - -export class DashlaneCsvImporter extends BaseImporter implements Importer { - parse(data: string): ImportResult { - const result = new ImportResult(); - const results = this.parseCsv(data, false); - if (results == null) { - result.success = false; - return result; - } - - results.forEach((value) => { - let skip = false; - if (value.length < 2) { - return; - } - - const cipher = this.initLoginCipher(); - cipher.name = this.getValueOrDefault(value[0], '--'); - - if (value.length === 2) { - cipher.login.uris = this.makeUriArray(value[1]); - } else if (value.length === 3) { - cipher.login.uris = this.makeUriArray(value[1]); - cipher.login.username = this.getValueOrDefault(value[2]); - } else if (value.length === 4) { - if (this.isNullOrWhitespace(value[2]) && this.isNullOrWhitespace(value[3])) { - cipher.login.username = value[1]; - cipher.notes = value[2] + '\n' + value[3]; - } else { - cipher.login.username = value[2]; - cipher.notes = value[1] + '\n' + value[3]; - } - } else if (value.length === 5) { - cipher.login.uris = this.makeUriArray(value[1]); - cipher.login.username = this.getValueOrDefault(value[2]); - cipher.login.password = this.getValueOrDefault(value[3]); - cipher.notes = this.getValueOrDefault(value[4]); - } else if (value.length === 6) { - if (this.isNullOrWhitespace(value[2])) { - cipher.login.username = this.getValueOrDefault(value[3]); - cipher.login.password = this.getValueOrDefault(value[4]); - cipher.notes = this.getValueOrDefault(value[5]); - } else { - cipher.login.username = this.getValueOrDefault(value[2]); - cipher.login.password = this.getValueOrDefault(value[3]); - cipher.notes = this.getValueOrDefault(value[4], '') + '\n' + this.getValueOrDefault(value[5], ''); - } - cipher.login.uris = this.makeUriArray(value[1]); - } else if (value.length === 7) { - if (this.isNullOrWhitespace(value[2])) { - cipher.login.username = this.getValueOrDefault(value[3]); - cipher.notes = this.getValueOrDefault(value[4], '') + '\n' + this.getValueOrDefault(value[6], ''); - } else { - cipher.login.username = this.getValueOrDefault(value[2]); - cipher.notes = this.getValueOrDefault(value[3], '') + '\n' + - this.getValueOrDefault(value[4], '') + '\n' + this.getValueOrDefault(value[6], ''); - } - cipher.login.uris = this.makeUriArray(value[1]); - cipher.login.password = this.getValueOrDefault(value[5]); - } else { - for (let i = 1; i < value.length; i++) { - cipher.notes += (value[i] + '\n'); - if (value[i] === 'NO_TYPE') { - skip = true; - break; - } - } - } - - if (skip) { - return; - } - if (this.isNullOrWhitespace(cipher.login.username)) { - cipher.login.username = null; - } - if (this.isNullOrWhitespace(cipher.login.password)) { - cipher.login.password = null; - } - this.cleanupCipher(cipher); - result.ciphers.push(cipher); - }); - - result.success = true; - return result; - } -} diff --git a/src/importers/dashlaneJsonImporter.ts b/src/importers/dashlaneJsonImporter.ts new file mode 100644 index 0000000000..582f3180c5 --- /dev/null +++ b/src/importers/dashlaneJsonImporter.ts @@ -0,0 +1,164 @@ +import { BaseImporter } from './baseImporter'; +import { Importer } from './importer'; + +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 { CipherType } from '../enums/cipherType'; + +const HandledResults = new Set(['ADDRESS', 'AUTHENTIFIANT', 'BANKSTATEMENT', 'IDCARD', 'IDENTITY', + 'PAYMENTMEANS_CREDITCARD', 'PAYMENTMEAN_PAYPAL', 'EMAIL']); + +export class DashlaneJsonImporter extends BaseImporter implements Importer { + private result: ImportResult; + + parse(data: string): ImportResult { + this.result = new ImportResult(); + const results = JSON.parse(data); + if (results == null || results.length === 0) { + this.result.success = false; + return this.result; + } + + if (results.ADDRESS != null) { + this.processAddress(results.ADDRESS); + } + if (results.AUTHENTIFIANT != null) { + this.processAuth(results.AUTHENTIFIANT); + } + if (results.BANKSTATEMENT != null) { + this.processNote(results.BANKSTATEMENT, 'BankAccountName'); + } + if (results.IDCARD != null) { + this.processNote(results.IDCARD, 'Fullname'); + } + if (results.PAYMENTMEANS_CREDITCARD != null) { + this.processCard(results.PAYMENTMEANS_CREDITCARD); + } + if (results.IDENTITY != null) { + this.processIdentity(results.IDENTITY); + } + + for (const key in results) { + if (results.hasOwnProperty(key) && !HandledResults.has(key)) { + this.processNote(results[key], null, 'Generic Note'); + } + } + + this.result.success = true; + return this.result; + } + + private processAuth(results: any[]) { + results.forEach((credential: any) => { + const cipher = this.initLoginCipher(); + cipher.name = this.getValueOrDefault(credential.title); + + cipher.login.username = this.getValueOrDefault(credential.login, + this.getValueOrDefault(credential.secondaryLogin)); + if (this.isNullOrWhitespace(cipher.login.username)) { + cipher.login.username = this.getValueOrDefault(credential.email); + } else if (!this.isNullOrWhitespace(credential.email)) { + cipher.notes = ('Email: ' + credential.email + '\n'); + } + + cipher.login.password = this.getValueOrDefault(credential.password); + cipher.login.uris = this.makeUriArray(credential.domain); + cipher.notes += this.getValueOrDefault(credential.note, ''); + + this.convertToNoteIfNeeded(cipher); + this.cleanupCipher(cipher); + this.result.ciphers.push(cipher); + }); + } + + private processIdentity(results: any[]) { + results.forEach((obj: any) => { + const cipher = new CipherView(); + cipher.identity = new IdentityView(); + cipher.type = CipherType.Identity; + cipher.name = this.getValueOrDefault(obj.fullName, ''); + const nameParts = cipher.name.split(' '); + if (nameParts.length > 0) { + cipher.identity.firstName = this.getValueOrDefault(nameParts[0]); + } + if (nameParts.length === 2) { + cipher.identity.lastName = this.getValueOrDefault(nameParts[1]); + } else if (nameParts.length === 3) { + cipher.identity.middleName = this.getValueOrDefault(nameParts[1]); + cipher.identity.lastName = this.getValueOrDefault(nameParts[2]); + } + cipher.identity.username = this.getValueOrDefault(obj.pseudo); + this.cleanupCipher(cipher); + this.result.ciphers.push(cipher); + }); + } + + private processAddress(results: any[]) { + results.forEach((obj: any) => { + const cipher = new CipherView(); + cipher.identity = new IdentityView(); + cipher.type = CipherType.Identity; + cipher.name = this.getValueOrDefault(obj.addressName); + cipher.identity.address1 = this.getValueOrDefault(obj.addressFull); + cipher.identity.city = this.getValueOrDefault(obj.city); + cipher.identity.state = this.getValueOrDefault(obj.state); + cipher.identity.postalCode = this.getValueOrDefault(obj.zipcode); + cipher.identity.country = this.getValueOrDefault(obj.country); + if (cipher.identity.country != null) { + cipher.identity.country = cipher.identity.country.toUpperCase(); + } + this.cleanupCipher(cipher); + this.result.ciphers.push(cipher); + }); + } + + private processCard(results: any[]) { + results.forEach((obj: any) => { + const cipher = new CipherView(); + cipher.card = new CardView(); + cipher.type = CipherType.Card; + cipher.name = this.getValueOrDefault(obj.bank); + cipher.card.number = this.getValueOrDefault(obj.cardNumber); + cipher.card.brand = this.getCardBrand(cipher.card.number); + cipher.card.cardholderName = this.getValueOrDefault(obj.owner); + if (!this.isNullOrWhitespace(cipher.card.brand)) { + if (this.isNullOrWhitespace(cipher.name)) { + cipher.name = cipher.card.brand; + } else { + cipher.name += (' - ' + cipher.card.brand); + } + } + this.cleanupCipher(cipher); + this.result.ciphers.push(cipher); + }); + } + + private processNote(results: any[], nameProperty: string, name: string = null) { + results.forEach((obj: any) => { + const cipher = new CipherView(); + cipher.secureNote = new SecureNoteView(); + cipher.type = CipherType.SecureNote; + if (name != null) { + cipher.name = name; + } else { + cipher.name = this.getValueOrDefault(obj[nameProperty]); + } + cipher.notes = ''; + for (const key in obj) { + if (obj.hasOwnProperty(key) && key !== nameProperty) { + const val = obj[key].toString(); + if (!this.isNullOrWhitespace(val)) { + cipher.notes += (key + ': ' + obj[key].toString() + '\n'); + } + } + } + this.cleanupCipher(cipher); + this.result.ciphers.push(cipher); + }); + } +} diff --git a/src/services/import.service.ts b/src/services/import.service.ts index c35f916259..784f90ab00 100644 --- a/src/services/import.service.ts +++ b/src/services/import.service.ts @@ -25,7 +25,7 @@ import { BitwardenCsvImporter } from '../importers/bitwardenCsvImporter'; import { BlurCsvImporter } from '../importers/blurCsvImporter'; import { ChromeCsvImporter } from '../importers/chromeCsvImporter'; import { ClipperzHtmlImporter } from '../importers/clipperzHtmlImporter'; -import { DashlaneCsvImporter } from '../importers/dashlaneCsvImporter'; +import { DashlaneJsonImporter } from '../importers/dashlaneJsonImporter'; import { EnpassCsvImporter } from '../importers/enpassCsvImporter'; import { FirefoxCsvImporter } from '../importers/firefoxCsvImporter'; import { GnomeJsonImporter } from '../importers/gnomeJsonImporter'; @@ -63,7 +63,7 @@ export class ImportService implements ImportServiceAbstraction { { id: 'firefoxcsv', name: 'Firefox (csv)' }, { id: 'keepass2xml', name: 'KeePass 2 (xml)' }, { id: '1password1pif', name: '1Password (1pif)' }, - { id: 'dashlanecsv', name: 'Dashlane (csv)' }, + { id: 'dashlanejson', name: 'Dashlane (json)' }, ]; regularImportOptions: ImportOption[] = [ @@ -185,8 +185,8 @@ export class ImportService implements ImportServiceAbstraction { return new EnpassCsvImporter(); case 'pwsafexml': return new PasswordSafeXmlImporter(); - case 'dashlanecsv': - return new DashlaneCsvImporter(); + case 'dashlanejson': + return new DashlaneJsonImporter(); case 'msecurecsv': return new MSecureCsvImporter(); case 'stickypasswordxml':