diff --git a/src/importers/baseImporter.ts b/src/importers/baseImporter.ts index 76069e261b..67d9f3f62e 100644 --- a/src/importers/baseImporter.ts +++ b/src/importers/baseImporter.ts @@ -227,6 +227,31 @@ export abstract class BaseImporter { return null; } + protected setCardExpiration(cipher: CipherView, expiration: string): boolean { + if (!this.isNullOrWhitespace(expiration)) { + const parts = expiration.split('/'); + if (parts.length === 2) { + let month: string = null; + let year: string = null; + if (parts[0].length === 1 || parts[0].length === 2) { + month = parts[0]; + if (month.length === 2 && month[0] === '0') { + month = month.substr(1, 1); + } + } + if (parts[1].length === 2 || parts[1].length === 4) { + year = month.length === 2 ? '20' + parts[1] : parts[1]; + } + if (month != null && year != null) { + cipher.card.expMonth = month; + cipher.card.expYear = year; + return true; + } + } + } + return false; + } + protected moveFoldersToCollections(result: ImportResult) { result.folderRelationships.forEach((r) => result.collectionRelationships.push(r)); result.collections = result.folders.map((f) => { diff --git a/src/importers/enpassCsvImporter.ts b/src/importers/enpassCsvImporter.ts index bf5bd5fb57..02fa9ab3ca 100644 --- a/src/importers/enpassCsvImporter.ts +++ b/src/importers/enpassCsvImporter.ts @@ -81,24 +81,8 @@ export class EnpassCsvImporter extends BaseImporter implements Importer { continue; } else if (fieldNameLower === 'expiry date' && this.isNullOrWhitespace(cipher.card.expMonth) && this.isNullOrWhitespace(cipher.card.expYear)) { - const parts = fieldValue.split('/'); - if (parts.length === 2) { - let month: string = null; - let year: string = null; - if (parts[0].length === 1 || parts[0].length === 2) { - month = parts[0]; - if (month.length === 2 && month[0] === '0') { - month = month.substr(1, 1); - } - } - if (parts[1].length === 2 || parts[1].length === 4) { - year = month.length === 2 ? '20' + parts[1] : parts[1]; - } - if (month != null && year != null) { - cipher.card.expMonth = month; - cipher.card.expYear = year; - continue; - } + if (this.setCardExpiration(cipher, fieldValue)) { + continue; } } else if (fieldNameLower === 'type') { // Skip since brand was determined from number above diff --git a/src/importers/enpassJsonImporter.ts b/src/importers/enpassJsonImporter.ts index 1a76a2ce6a..b21e454e51 100644 --- a/src/importers/enpassJsonImporter.ts +++ b/src/importers/enpassJsonImporter.ts @@ -84,24 +84,7 @@ export class EnpassJsonImporter extends BaseImporter implements Importer { } else if (field.type === 'ccCvc' && this.isNullOrWhitespace(cipher.card.code)) { cipher.card.code = field.value; } else if (field.type === 'ccExpiry' && this.isNullOrWhitespace(cipher.card.expYear)) { - const parts = field.value.split('/'); - if (parts.length === 2) { - let month: string = null; - let year: string = null; - if (parts[0].length === 1 || parts[0].length === 2) { - month = parts[0]; - if (month.length === 2 && month[0] === '0') { - month = month.substr(1, 1); - } - } - if (parts[1].length === 2 || parts[1].length === 4) { - year = month.length === 2 ? '20' + parts[1] : parts[1]; - } - if (month != null && year != null) { - cipher.card.expMonth = month; - cipher.card.expYear = year; - } - } else { + if (!this.setCardExpiration(cipher, field.value)) { this.processKvp(cipher, field.label, field.value); } } else { diff --git a/src/importers/fsecureFskImporter.ts b/src/importers/fsecureFskImporter.ts new file mode 100644 index 0000000000..81ca6d5f30 --- /dev/null +++ b/src/importers/fsecureFskImporter.ts @@ -0,0 +1,60 @@ +import { BaseImporter } from './baseImporter'; +import { Importer } from './importer'; + +import { ImportResult } from '../models/domain/importResult'; + +import { CardView } from '../models/view/cardView'; + +import { CipherType } from '../enums/cipherType'; + +export class FSecureFskImporter extends BaseImporter implements Importer { + parse(data: string): ImportResult { + const result = new ImportResult(); + const results = JSON.parse(data); + if (results == null || results.data == null) { + result.success = false; + return result; + } + + for (const key in results.data) { + if (!results.data.hasOwnProperty(key)) { + continue; + } + + const value = results.data[key]; + const cipher = this.initLoginCipher(); + cipher.name = this.getValueOrDefault(value.service); + cipher.notes = this.getValueOrDefault(value.notes); + + if (value.style === 'website') { + cipher.login.username = this.getValueOrDefault(value.username); + cipher.login.password = this.getValueOrDefault(value.password); + cipher.login.uris = this.makeUriArray(value.url); + } else if (value.style === 'creditcard') { + cipher.type = CipherType.Card; + cipher.card = new CardView(); + cipher.card.cardholderName = this.getValueOrDefault(value.username); + cipher.card.number = this.getValueOrDefault(value.creditNumber); + cipher.card.brand = this.getCardBrand(cipher.card.number); + cipher.card.code = this.getValueOrDefault(value.creditCvv); + if (!this.isNullOrWhitespace(value.creditExpiry)) { + if (!this.setCardExpiration(cipher, value.creditExpiry)) { + this.processKvp(cipher, 'Expiration', value.creditExpiry); + } + } + if (!this.isNullOrWhitespace(value.password)) { + this.processKvp(cipher, 'PIN', value.password); + } + } else { + continue; + } + + this.convertToNoteIfNeeded(cipher); + this.cleanupCipher(cipher); + result.ciphers.push(cipher); + } + + result.success = true; + return result; + } +} diff --git a/src/services/import.service.ts b/src/services/import.service.ts index fef62131d8..32a7a625c8 100644 --- a/src/services/import.service.ts +++ b/src/services/import.service.ts @@ -31,6 +31,7 @@ import { DashlaneJsonImporter } from '../importers/dashlaneJsonImporter'; import { EnpassCsvImporter } from '../importers/enpassCsvImporter'; import { EnpassJsonImporter } from '../importers/enpassJsonImporter'; import { FirefoxCsvImporter } from '../importers/firefoxCsvImporter'; +import { FSecureFskImporter } from '../importers/fsecureFskImporter'; import { GnomeJsonImporter } from '../importers/gnomeJsonImporter'; import { Importer } from '../importers/importer'; import { KeePass2XmlImporter } from '../importers/keepass2XmlImporter'; @@ -103,6 +104,7 @@ export class ImportService implements ImportServiceAbstraction { { id: 'passpackcsv', name: 'Passpack (csv)' }, { id: 'passmanjson', name: 'Passman (json)' }, { id: 'avastcsv', name: 'Avast Passwords (csv)' }, + { id: 'fsecurefsk', name: 'F-Secure KEY (fsk)' }, ]; constructor(private cipherService: CipherService, private folderService: FolderService, @@ -227,6 +229,8 @@ export class ImportService implements ImportServiceAbstraction { return new PassmanJsonImporter(); case 'avastcsv': return new AvastCsvImporter(); + case 'fsecurefsk': + return new FSecureFskImporter(); default: return null; }