1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-22 03:03:43 +00:00

Fix 1password importer (#222)

* Change cipher type based on csv type header

* Test identity and credit card import

* Do not use node 'fs' module

Karma is being used for automated tests so node modules are not available

* WIP: mac and windows 1password importer split

Need to improve windows field identification to limit secret data
exposure and improve user experience

* Hide fields with likely secret values

Co-authored-by: Matt Gibson <mdgibson@Matts-MBP.lan>
This commit is contained in:
Matt Gibson
2020-12-08 11:29:57 -06:00
committed by GitHub
parent 2d62e10d98
commit 72bf18f369
27 changed files with 587 additions and 245 deletions

View File

@@ -5,7 +5,7 @@ export abstract class CryptoFunctionService {
pbkdf2: (password: string | ArrayBuffer, salt: string | ArrayBuffer, algorithm: 'sha256' | 'sha512',
iterations: number) => Promise<ArrayBuffer>;
hkdf: (ikm: ArrayBuffer, salt: string | ArrayBuffer, info: string | ArrayBuffer,
outputByteSize: number, algorithm: 'sha256' | 'sha512') => Promise<ArrayBuffer>
outputByteSize: number, algorithm: 'sha256' | 'sha512') => Promise<ArrayBuffer>;
hkdfExpand: (prk: ArrayBuffer, info: string | ArrayBuffer, outputByteSize: number,
algorithm: 'sha256' | 'sha512') => Promise<ArrayBuffer>;
hash: (value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512' | 'md5') => Promise<ArrayBuffer>;

View File

@@ -246,7 +246,7 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
}
get authing(): boolean {
return this.authService.authingWithPassword() || this.authService.authingWithSso() || this.authService.authingWithApiKey()
return this.authService.authingWithPassword() || this.authService.authingWithSso() || this.authService.authingWithApiKey();
}
get needsLock(): boolean {

View File

@@ -68,7 +68,7 @@ export abstract class BaseImporter {
protected parseCsvOptions = {
encoding: 'UTF-8',
skipEmptyLines: false,
}
};
protected organization() {
return this.organizationId != null;

View File

@@ -0,0 +1,8 @@
import { CipherView } from '../../models/view';
export class CipherImportContext {
lowerProperty: string;
constructor(public importRecord: any, public property: string, public cipher: CipherView) {
this.lowerProperty = property.toLowerCase();
}
}

View File

@@ -1,17 +1,17 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { BaseImporter } from '../baseImporter';
import { Importer } from '../importer';
import { ImportResult } from '../models/domain/importResult';
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 { PasswordHistoryView } from '../models/view/passwordHistoryView';
import { SecureNoteView } from '../models/view/secureNoteView';
import { CardView } from '../../models/view/cardView';
import { CipherView } from '../../models/view/cipherView';
import { IdentityView } from '../../models/view/identityView';
import { PasswordHistoryView } from '../../models/view/passwordHistoryView';
import { SecureNoteView } from '../../models/view/secureNoteView';
import { CipherType } from '../enums/cipherType';
import { FieldType } from '../enums/fieldType';
import { SecureNoteType } from '../enums/secureNoteType';
import { CipherType } from '../../enums/cipherType';
import { FieldType } from '../../enums/fieldType';
import { SecureNoteType } from '../../enums/secureNoteType';
export class OnePassword1PifImporter extends BaseImporter implements Importer {
result = new ImportResult();

View File

@@ -0,0 +1,288 @@
import { ImportResult } from '../../models/domain/importResult';
import { BaseImporter } from '../baseImporter';
import { Importer } from '../importer';
import { CipherType } from '../../enums/cipherType';
import { FieldType } from '../../enums/fieldType';
import { CipherView } from '../../models/view';
import { CipherImportContext } from './cipherImportContext';
export const IgnoredProperties = ['ainfo', 'autosubmit', 'notesplain', 'ps', 'scope', 'tags', 'title', 'uuid', 'notes'];
export abstract class OnePasswordCsvImporter extends BaseImporter implements Importer {
protected loginPropertyParsers = [this.setLoginUsername, this.setLoginPassword, this.setLoginUris];
protected creditCardPropertyParsers = [this.setCreditCardNumber, this.setCreditCardVerification, this.setCreditCardCardholderName, this.setCreditCardExpiry];
protected identityPropertyParsers = [this.setIdentityFirstName, this.setIdentityInitial, this.setIdentityLastName, this.setIdentityUserName, this.setIdentityEmail, this.setIdentityPhone, this.setIdentityCompany];
abstract setCipherType(value: any, cipher: CipherView): void;
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true, {
quoteChar: '"',
escapeChar: '\\',
});
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach((value) => {
if (this.isNullOrWhitespace(this.getProp(value, 'title'))) {
return;
}
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(this.getProp(value, 'title'), '--');
this.setNotes(value, cipher);
this.setCipherType(value, cipher);
let altUsername: string = null;
for (const property in value) {
if (!value.hasOwnProperty(property) || this.isNullOrWhitespace(value[property])) {
continue;
}
const context = new CipherImportContext(value, property, cipher);
if (cipher.type === CipherType.Login && this.setKnownLoginValue(context)) {
continue;
} else if (cipher.type === CipherType.Card && this.setKnownCreditCardValue(context)) {
continue;
} else if (cipher.type === CipherType.Identity && this.setKnownIdentityValue(context)) {
continue;
}
altUsername = this.setUnknownValue(context, altUsername);
}
if (cipher.type === CipherType.Login && !this.isNullOrWhitespace(altUsername) &&
this.isNullOrWhitespace(cipher.login.username) && altUsername.indexOf('://') === -1) {
cipher.login.username = altUsername;
}
this.convertToNoteIfNeeded(cipher);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
protected getProp(obj: any, name: string): any {
const lowerObj = Object.entries(obj).reduce((agg: any, entry: [string, any]) => {
agg[entry[0].toLowerCase()] = entry[1];
return agg;
}, {});
return lowerObj[name.toLowerCase()];
}
protected getPropByRegexp(obj: any, regexp: RegExp): any {
const matchingKeys = Object.keys(obj).reduce((agg: string[], key: string) => {
if (key.match(regexp)) {
agg.push(key);
}
return agg;
}, []);
if (matchingKeys.length === 0) {
return null;
} else {
return obj[matchingKeys[0]];
}
}
protected getPropIncluding(obj: any, name: string): any {
const includesMap = Object.keys(obj).reduce((agg: string[], entry: string) => {
if (entry.toLowerCase().includes(name.toLowerCase())) {
agg.push(entry);
}
return agg;
}, []);
if (includesMap.length === 0) {
return null;
} else {
return obj[includesMap[0]];
}
}
protected setNotes(importRecord: any, cipher: CipherView) {
cipher.notes = this.getValueOrDefault(this.getProp(importRecord, 'notesPlain'), '') + '\n' +
this.getValueOrDefault(this.getProp(importRecord, 'notes'), '') + '\n';
cipher.notes.trim();
}
protected setKnownLoginValue(context: CipherImportContext): boolean {
return this.loginPropertyParsers.reduce((agg: boolean, func) => {
if (!agg) {
agg = func.bind(this)(context);
}
return agg;
}, false);
}
protected setKnownCreditCardValue(context: CipherImportContext): boolean {
return this.creditCardPropertyParsers.reduce((agg: boolean, func) => {
if (!agg) {
agg = func.bind(this)(context);
}
return agg;
}, false);
}
protected setKnownIdentityValue(context: CipherImportContext): boolean {
return this.identityPropertyParsers.reduce((agg: boolean, func) => {
if (!agg) {
agg = func.bind(this)(context);
}
return agg;
}, false);
}
protected setUnknownValue(context: CipherImportContext, altUsername: string): string {
if (IgnoredProperties.indexOf(context.lowerProperty) === -1 && !context.lowerProperty.startsWith('section:') &&
!context.lowerProperty.startsWith('section ')) {
if (altUsername == null && context.lowerProperty === 'email') {
return context.importRecord[context.property];
}
else if (context.lowerProperty === 'created date' || context.lowerProperty === 'modified date') {
const readableDate = new Date(parseInt(context.importRecord[context.property], 10) * 1000).toUTCString();
this.processKvp(context.cipher, '1Password ' + context.property, readableDate);
return null;
}
if (context.lowerProperty.includes('password') || context.lowerProperty.includes('key') || context.lowerProperty.includes('secret')) {
this.processKvp(context.cipher, context.property, context.importRecord[context.property], FieldType.Hidden);
} else {
this.processKvp(context.cipher, context.property, context.importRecord[context.property]);
}
}
return null;
}
protected setIdentityFirstName(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.identity.firstName) && context.lowerProperty.includes('first name')) {
context.cipher.identity.firstName = context.importRecord[context.property];
return true;
}
return false;
}
protected setIdentityInitial(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.identity.middleName) && context.lowerProperty.includes('initial')) {
context.cipher.identity.middleName = context.importRecord[context.property];
return true;
}
return false;
}
protected setIdentityLastName(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.identity.lastName) && context.lowerProperty.includes('last name')) {
context.cipher.identity.lastName = context.importRecord[context.property];
return true;
}
return false;
}
protected setIdentityUserName(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.identity.username) && context.lowerProperty.includes('username')) {
context.cipher.identity.username = context.importRecord[context.property];
return true;
}
return false;
}
protected setIdentityCompany(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.identity.company) && context.lowerProperty.includes('company')) {
context.cipher.identity.company = context.importRecord[context.property];
return true;
}
return false;
}
protected setIdentityPhone(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.identity.phone) && context.lowerProperty.includes('default phone')) {
context.cipher.identity.phone = context.importRecord[context.property];
return true;
}
return false;
}
protected setIdentityEmail(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.identity.email) && context.lowerProperty.includes('email')) {
context.cipher.identity.email = context.importRecord[context.property];
return true;
}
return false;
}
protected setCreditCardNumber(context: CipherImportContext): boolean {
if (this.isNullOrWhitespace(context.cipher.card.number) && context.lowerProperty.includes('number')) {
context.cipher.card.number = context.importRecord[context.property];
context.cipher.card.brand = this.getCardBrand(context.cipher.card.number);
return true;
}
return false;
}
protected setCreditCardVerification(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.card.code) && context.lowerProperty.includes('verification number')) {
context.cipher.card.code = context.importRecord[context.property];
return true;
}
return false;
}
protected setCreditCardCardholderName(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.card.cardholderName) && context.lowerProperty.includes('cardholder name')) {
context.cipher.card.cardholderName = context.importRecord[context.property];
return true;
}
return false;
}
protected setCreditCardExpiry(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.card.expiration) && context.lowerProperty.includes('expiry date') &&
context.importRecord[context.property].length === 7) {
context.cipher.card.expMonth = (context.importRecord[context.property] as string).substr(0, 2);
if (context.cipher.card.expMonth[0] === '0') {
context.cipher.card.expMonth = context.cipher.card.expMonth.substr(1, 1);
}
context.cipher.card.expYear = (context.importRecord[context.property] as string).substr(3, 4);
return true;
}
return false;
}
protected setLoginPassword(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.login.password) && context.lowerProperty === 'password') {
context.cipher.login.password = context.importRecord[context.property];
return true;
}
return false;
}
protected setLoginUsername(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.login.username) && context.lowerProperty === 'username') {
context.cipher.login.username = context.importRecord[context.property];
return true;
}
return false;
}
protected setLoginUris(context: CipherImportContext) {
if ((context.cipher.login.uris == null || context.cipher.login.uris.length === 0) && context.lowerProperty === 'urls') {
const urls = context.importRecord[context.property].split(this.newLineRegex);
context.cipher.login.uris = this.makeUriArray(urls);
return true;
} else if ((context.lowerProperty === 'url')) {
if (context.cipher.login.uris == null) {
context.cipher.login.uris = [];
}
context.cipher.login.uris.concat(this.makeUriArray(context.importRecord[context.property]));
return true;
}
return false;
}
}

View File

@@ -0,0 +1,28 @@
import { Importer } from '../importer';
import { IgnoredProperties, OnePasswordCsvImporter } from './onepasswordCsvImporter';
import { CipherType } from '../../enums/cipherType';
import { CardView, CipherView, IdentityView } from '../../models/view';
export class OnePasswordMacCsvImporter extends OnePasswordCsvImporter implements Importer {
setCipherType(value: any, cipher: CipherView) {
const onePassType = this.getValueOrDefault(this.getProp(value, 'type'), 'Login');
switch (onePassType) {
case 'Credit Card':
cipher.type = CipherType.Card;
cipher.card = new CardView();
IgnoredProperties.push('type');
break;
case 'Identity':
cipher.type = CipherType.Identity;
cipher.identity = new IdentityView();
IgnoredProperties.push('type');
break;
case 'Login':
case 'Secure Note':
IgnoredProperties.push('type');
default:
break;
}
}
}

View File

@@ -0,0 +1,53 @@
import { Importer } from '../importer';
import { CipherImportContext } from './cipherImportContext';
import { OnePasswordCsvImporter } from './onepasswordCsvImporter';
import { CipherType } from '../../enums/cipherType';
import { CardView, CipherView, IdentityView, LoginView } from '../../models/view';
export class OnePasswordWinCsvImporter extends OnePasswordCsvImporter implements Importer {
constructor() {
super();
this.identityPropertyParsers.push(this.setIdentityAddress);
}
setCipherType(value: any, cipher: CipherView) {
cipher.type = CipherType.Login;
cipher.login = new LoginView();
if (!this.isNullOrWhitespace(this.getPropByRegexp(value, /\d+: number/i)) &&
!this.isNullOrWhitespace(this.getPropByRegexp(value, /\d+: expiry date/i))) {
cipher.type = CipherType.Card;
cipher.card = new CardView();
}
if (!this.isNullOrWhitespace(this.getPropByRegexp(value, /name \d+: first name/i)) ||
!this.isNullOrWhitespace(this.getPropByRegexp(value, /name \d+: initial/i)) ||
!this.isNullOrWhitespace(this.getPropByRegexp(value, /name \d+: last name/i)) ||
!this.isNullOrWhitespace(this.getPropByRegexp(value, /internet \d+: email/i))) {
cipher.type = CipherType.Identity;
cipher.identity = new IdentityView();
}
}
setIdentityAddress(context: CipherImportContext) {
if (context.lowerProperty.match(/address \d+: address/i)) {
this.processKvp(context.cipher, 'address', context.importRecord[context.property]);
return true;
}
return false;
}
setCreditCardExpiry(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.card.expiration) && context.lowerProperty.includes('expiry date')) {
const expSplit = (context.importRecord[context.property] as string).split('/');
context.cipher.card.expMonth = expSplit[0];
if (context.cipher.card.expMonth[0] === '0' && context.cipher.card.expMonth.length === 2) {
context.cipher.card.expMonth = context.cipher.card.expMonth.substr(1, 1);
}
context.cipher.card.expYear = expSplit[2].length > 4 ? expSplit[2].substr(0, 4) : expSplit[2];
return true;
}
return false;
}
}

View File

@@ -1,168 +0,0 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
import { CipherType } from '../enums/cipherType';
import { CardView, IdentityView } from '../models/view';
const IgnoredProperties = ['ainfo', 'autosubmit', 'notesplain', 'ps', 'scope', 'tags', 'title', 'uuid', 'notes'];
export class OnePasswordWinCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true, {
quoteChar: '"',
escapeChar: '\\',
});
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach((value) => {
if (this.isNullOrWhitespace(this.getProp(value, 'title'))) {
return;
}
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(this.getProp(value, 'title'), '--');
cipher.notes = this.getValueOrDefault(this.getProp(value, 'notesPlain'), '') + '\n' +
this.getValueOrDefault(this.getProp(value, 'notes'), '') + '\n';
cipher.notes.trim();
const onePassType = this.getValueOrDefault(this.getProp(value, 'type'), 'Login')
switch (onePassType) {
case 'Credit Card':
cipher.type = CipherType.Card;
cipher.card = new CardView();
IgnoredProperties.push('type');
break;
case 'Identity':
cipher.type = CipherType.Identity;
cipher.identity = new IdentityView();
IgnoredProperties.push('type');
break;
case 'Login':
case 'Secure Note':
IgnoredProperties.push('type');
default:
break;
}
if (!this.isNullOrWhitespace(this.getProp(value, 'number')) &&
!this.isNullOrWhitespace(this.getProp(value, 'expiry date'))) {
cipher.type = CipherType.Card;
cipher.card = new CardView();
}
let altUsername: string = null;
for (const property in value) {
if (!value.hasOwnProperty(property) || this.isNullOrWhitespace(value[property])) {
continue;
}
const lowerProp = property.toLowerCase();
if (cipher.type === CipherType.Login) {
if (this.isNullOrWhitespace(cipher.login.password) && lowerProp === 'password') {
cipher.login.password = value[property];
continue;
} else if (this.isNullOrWhitespace(cipher.login.username) && lowerProp === 'username') {
cipher.login.username = value[property];
continue;
} else if ((cipher.login.uris == null || cipher.login.uri.length === 0) && lowerProp === 'urls') {
const urls = value[property].split(this.newLineRegex);
cipher.login.uris = this.makeUriArray(urls);
continue;
} else if ((lowerProp === 'url')) {
if (cipher.login.uris == null) {
cipher.login.uris = [];
}
cipher.login.uris.concat(this.makeUriArray(value[property]));
continue;
}
} else if (cipher.type === CipherType.Card) {
if (this.isNullOrWhitespace(cipher.card.number) && lowerProp.includes('number')) {
cipher.card.number = value[property];
cipher.card.brand = this.getCardBrand(this.getProp(value, 'number'));
continue;
} else if (this.isNullOrWhitespace(cipher.card.code) && lowerProp.includes('verification number')) {
cipher.card.code = value[property];
continue;
} else if (this.isNullOrWhitespace(cipher.card.cardholderName) && lowerProp.includes('cardholder name')) {
cipher.card.cardholderName = value[property];
continue;
} else if (this.isNullOrWhitespace(cipher.card.expiration) && lowerProp.includes('expiry date') &&
value[property].length === 7) {
cipher.card.expMonth = (value[property] as string).substr(0, 2);
if (cipher.card.expMonth[0] === '0') {
cipher.card.expMonth = cipher.card.expMonth.substr(1, 1);
}
cipher.card.expYear = (value[property] as string).substr(3, 4);
continue;
} else if (lowerProp === 'type' || lowerProp === 'type(type)') {
// Skip since brand was determined from number above
continue;
}
} else if (cipher.type === CipherType.Identity) {
if (this.isNullOrWhitespace(cipher.identity.firstName) && lowerProp.includes('first name')) {
cipher.identity.firstName = value[property];
continue;
} else if (this.isNullOrWhitespace(cipher.identity.middleName) && lowerProp.includes('initial')) {
cipher.identity.middleName = value[property];
continue;
} else if (this.isNullOrWhitespace(cipher.identity.lastName) && lowerProp.includes('last name')) {
cipher.identity.lastName = value[property];
continue;
} else if (this.isNullOrWhitespace(cipher.identity.username) && lowerProp.includes('username')) {
cipher.identity.username = value[property];
continue;
} else if (this.isNullOrWhitespace(cipher.identity.company) && lowerProp.includes('company')) {
cipher.identity.company = value[property];
continue;
} else if (this.isNullOrWhitespace(cipher.identity.phone) && lowerProp.includes('default phone')) {
cipher.identity.phone = value[property];
continue;
} else if (this.isNullOrWhitespace(cipher.identity.email) && lowerProp.includes('email')) {
cipher.identity.email = value[property];
continue;
}
}
if (IgnoredProperties.indexOf(lowerProp) === -1 && !lowerProp.startsWith('section:') &&
!lowerProp.startsWith('section ')) {
if (altUsername == null && lowerProp === 'email') {
altUsername = value[property];
}
else if (lowerProp === 'created date' || lowerProp === 'modified date') {
const readableDate = new Date(parseInt(value[property], 10) * 1000).toUTCString();
this.processKvp(cipher, '1Password ' + property, readableDate);
continue;
}
this.processKvp(cipher, property, value[property]);
}
}
if (cipher.type === CipherType.Login && !this.isNullOrWhitespace(altUsername) &&
this.isNullOrWhitespace(cipher.login.username) && altUsername.indexOf('://') === -1) {
cipher.login.username = altUsername;
}
this.convertToNoteIfNeeded(cipher);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
private getProp(obj: any, name: string): any {
const lowerObj = Object.entries(obj).reduce((agg: any, entry: [string, any]) => {
agg[entry[0].toLowerCase()] = entry[1];
return agg;
}, {});
return lowerObj[name.toLowerCase()];
}
}

View File

@@ -94,7 +94,7 @@ export class Utils {
}
static fromBufferToUrlB64(buffer: ArrayBuffer): string {
return Utils.fromB64toUrlB64(Utils.fromBufferToB64(buffer))
return Utils.fromB64toUrlB64(Utils.fromBufferToB64(buffer));
}
static fromB64toUrlB64(b64Str: string) {

View File

@@ -1,6 +1,6 @@
import { SendType } from '../../enums/sendType';
import { SendFileApi } from '../api/sendFileApi'
import { SendFileApi } from '../api/sendFileApi';
import { SendTextApi } from '../api/sendTextApi';
import { Send } from '../domain/send';

View File

@@ -25,8 +25,8 @@ export class TokenRequest {
this.codeVerifier = codes[1];
this.redirectUri = codes[2];
} else if (clientIdClientSecret != null && clientIdClientSecret.length > 1) {
this.clientId = clientIdClientSecret[0]
this.clientSecret = clientIdClientSecret[1]
this.clientId = clientIdClientSecret[0];
this.clientSecret = clientIdClientSecret[1];
}
this.token = token;
this.provider = provider;

View File

@@ -283,7 +283,7 @@ export class AuthService implements AuthServiceAbstraction {
codeCodeVerifier = null;
}
if (clientId != null && clientSecret != null) {
clientIdClientSecret = [clientId, clientSecret]
clientIdClientSecret = [clientId, clientSecret];
} else {
clientIdClientSecret = null;
}

View File

@@ -52,8 +52,9 @@ import { LogMeOnceCsvImporter } from '../importers/logMeOnceCsvImporter';
import { MeldiumCsvImporter } from '../importers/meldiumCsvImporter';
import { MSecureCsvImporter } from '../importers/msecureCsvImporter';
import { MykiCsvImporter } from '../importers/mykiCsvImporter';
import { OnePassword1PifImporter } from '../importers/onepassword1PifImporter';
import { OnePasswordWinCsvImporter } from '../importers/onepasswordWinCsvImporter';
import { OnePassword1PifImporter } from '../importers/onepasswordImporters/onepassword1PifImporter';
import { OnePasswordMacCsvImporter } from '../importers/onepasswordImporters/onepasswordMacCsvImporter';
import { OnePasswordWinCsvImporter } from '../importers/onepasswordImporters/onepasswordWinCsvImporter';
import { PadlockCsvImporter } from '../importers/padlockCsvImporter';
import { PassKeepCsvImporter } from '../importers/passkeepCsvImporter';
import { PassmanJsonImporter } from '../importers/passmanJsonImporter';
@@ -90,6 +91,7 @@ export class ImportService implements ImportServiceAbstraction {
regularImportOptions: ImportOption[] = [
{ id: 'keepassxcsv', name: 'KeePassX (csv)' },
{ id: '1passwordwincsv', name: '1Password 6 and 7 Windows (csv)' },
{ id: '1passwordmaccsv', name: '1Password 6 and 7 Mac (csv)' },
{ id: 'roboformcsv', name: 'RoboForm (csv)' },
{ id: 'keepercsv', name: 'Keeper (csv)' },
{ id: 'enpasscsv', name: 'Enpass (csv)' },
@@ -215,6 +217,8 @@ export class ImportService implements ImportServiceAbstraction {
return new OnePassword1PifImporter();
case '1passwordwincsv':
return new OnePasswordWinCsvImporter();
case '1passwordmaccsv':
return new OnePasswordMacCsvImporter();
case 'keepercsv':
return new KeeperCsvImporter();
case 'passworddragonxml':