[PS-1755] BEEEP: FSecure FSK-Importer improvements (#3877)
* Move FsecureFskImporter into separate folder * Add types for exported fsk file * Add new testdata and rewrite existing tests * Fix #2801 - Use type instead of style property to differentiate between cipher types * Add setting cipher.favorite * Remove unmapped property autofillAndroid * Re-naming files due to new naming convention Renamed added or changed files of this PR Fixed all imports Removed items from the whitelist * Extract method refactor Move logic inside of parse loop into parseEntry Extract handling of Entries of type Login into handleLoginEntry Extract handling of Entries of type CreditCard into handleCreditCardEntry * Simplify folder structure Use vendor name importer folder Rename /importers/fsecureImporters to /importers/fsecure Move fsecure-fsk-types.ts out of the types folder into the fsecure-folder Delete types folder Fix all the imports * Move spec and test-data to fsecure importer * Fix broken import after merge master * Use the new FSecureFskImporter Must have messed up during the last merge: Delete old importer and spec Fix import of FSecureFskImporter in import.service
This commit is contained in:
parent
3a98b415b0
commit
d6acc77ba7
|
@ -1,77 +0,0 @@
|
|||
import { FSecureFskImporter as Importer } from "@bitwarden/common/importers/fsecure-fsk-importer";
|
||||
|
||||
const TestDataWithStyleSetToWebsite: string = JSON.stringify({
|
||||
data: {
|
||||
"8d58b5cf252dd06fbd98f5289e918ab1": {
|
||||
color: "#00baff",
|
||||
reatedDate: 1609302913,
|
||||
creditCvv: "",
|
||||
creditExpiry: "",
|
||||
creditNumber: "",
|
||||
favorite: 0,
|
||||
modifiedDate: 1609302913,
|
||||
notes: "note",
|
||||
password: "word",
|
||||
passwordList: [],
|
||||
passwordModifiedDate: 1609302913,
|
||||
rev: 1,
|
||||
service: "My first pass",
|
||||
style: "website",
|
||||
type: 1,
|
||||
url: "https://bitwarden.com",
|
||||
username: "pass",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const TestDataWithStyleSetToGlobe: string = JSON.stringify({
|
||||
data: {
|
||||
"8d58b5cf252dd06fbd98f5289e918ab1": {
|
||||
color: "#00baff",
|
||||
reatedDate: 1609302913,
|
||||
creditCvv: "",
|
||||
creditExpiry: "",
|
||||
creditNumber: "",
|
||||
favorite: 0,
|
||||
modifiedDate: 1609302913,
|
||||
notes: "note",
|
||||
password: "word",
|
||||
passwordList: [],
|
||||
passwordModifiedDate: 1609302913,
|
||||
rev: 1,
|
||||
service: "My first pass",
|
||||
style: "globe",
|
||||
type: 1,
|
||||
url: "https://bitwarden.com",
|
||||
username: "pass",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
describe("FSecure FSK Importer", () => {
|
||||
it("should parse data with style set to website", async () => {
|
||||
const importer = new Importer();
|
||||
const result = await importer.parse(TestDataWithStyleSetToWebsite);
|
||||
expect(result != null).toBe(true);
|
||||
|
||||
const cipher = result.ciphers.shift();
|
||||
expect(cipher.login.username).toEqual("pass");
|
||||
expect(cipher.login.password).toEqual("word");
|
||||
expect(cipher.login.uris.length).toEqual(1);
|
||||
const uriView = cipher.login.uris.shift();
|
||||
expect(uriView.uri).toEqual("https://bitwarden.com");
|
||||
});
|
||||
|
||||
it("should parse data with style set to globe", async () => {
|
||||
const importer = new Importer();
|
||||
const result = await importer.parse(TestDataWithStyleSetToGlobe);
|
||||
expect(result != null).toBe(true);
|
||||
|
||||
const cipher = result.ciphers.shift();
|
||||
expect(cipher.login.username).toEqual("pass");
|
||||
expect(cipher.login.password).toEqual("word");
|
||||
expect(cipher.login.uris.length).toEqual(1);
|
||||
const uriView = cipher.login.uris.shift();
|
||||
expect(uriView.uri).toEqual("https://bitwarden.com");
|
||||
});
|
||||
});
|
|
@ -1,59 +0,0 @@
|
|||
import { CipherType } from "../enums/cipherType";
|
||||
import { ImportResult } from "../models/domain/import-result";
|
||||
import { CardView } from "../models/view/card.view";
|
||||
|
||||
import { BaseImporter } from "./base-importer";
|
||||
import { Importer } from "./importer";
|
||||
|
||||
export class FSecureFskImporter extends BaseImporter implements Importer {
|
||||
parse(data: string): Promise<ImportResult> {
|
||||
const result = new ImportResult();
|
||||
const results = JSON.parse(data);
|
||||
if (results == null || results.data == null) {
|
||||
result.success = false;
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
for (const key in results.data) {
|
||||
// eslint-disable-next-line
|
||||
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" || value.style === "globe") {
|
||||
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 Promise.resolve(result);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
import { CipherType } from "../../enums/cipherType";
|
||||
|
||||
import { FSecureFskImporter as Importer } from "./fsecure-fsk-importer";
|
||||
import { CreditCardTestEntry, LoginTestEntry } from "./fsk-test-data";
|
||||
|
||||
describe("FSecure FSK Importer", () => {
|
||||
it("should import data of type login", async () => {
|
||||
const importer = new Importer();
|
||||
const LoginTestEntryStringified = JSON.stringify(LoginTestEntry);
|
||||
const result = await importer.parse(LoginTestEntryStringified);
|
||||
expect(result != null).toBe(true);
|
||||
|
||||
const cipher = result.ciphers.shift();
|
||||
|
||||
expect(cipher.name).toEqual("example.com");
|
||||
expect(cipher.favorite).toBe(true);
|
||||
expect(cipher.notes).toEqual("some note for example.com");
|
||||
|
||||
expect(cipher.type).toBe(CipherType.Login);
|
||||
expect(cipher.login.username).toEqual("jdoe");
|
||||
expect(cipher.login.password).toEqual("somePassword");
|
||||
|
||||
expect(cipher.login.uris.length).toEqual(1);
|
||||
const uriView = cipher.login.uris.shift();
|
||||
expect(uriView.uri).toEqual("https://www.example.com");
|
||||
});
|
||||
|
||||
it("should import data of type creditCard", async () => {
|
||||
const importer = new Importer();
|
||||
const CreditCardTestEntryStringified = JSON.stringify(CreditCardTestEntry);
|
||||
const result = await importer.parse(CreditCardTestEntryStringified);
|
||||
expect(result != null).toBe(true);
|
||||
|
||||
const cipher = result.ciphers.shift();
|
||||
|
||||
expect(cipher.name).toEqual("My credit card");
|
||||
expect(cipher.favorite).toBe(false);
|
||||
expect(cipher.notes).toEqual("some notes to my card");
|
||||
|
||||
expect(cipher.type).toBe(CipherType.Card);
|
||||
expect(cipher.card.cardholderName).toEqual("John Doe");
|
||||
expect(cipher.card.number).toEqual("4242424242424242");
|
||||
expect(cipher.card.code).toEqual("123");
|
||||
|
||||
expect(cipher.fields.length).toBe(2);
|
||||
expect(cipher.fields[0].name).toEqual("Expiration");
|
||||
expect(cipher.fields[0].value).toEqual("22.10.2026");
|
||||
|
||||
expect(cipher.fields[1].name).toEqual("PIN");
|
||||
expect(cipher.fields[1].value).toEqual("1234");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,79 @@
|
|||
import { CipherType } from "../../enums/cipherType";
|
||||
import { ImportResult } from "../../models/domain/import-result";
|
||||
import { CardView } from "../../models/view/card.view";
|
||||
import { CipherView } from "../../models/view/cipher.view";
|
||||
import { BaseImporter } from "../base-importer";
|
||||
import { Importer } from "../importer";
|
||||
|
||||
import { FskEntry, FskEntryTypesEnum, FskFile } from "./fsecure-fsk-types";
|
||||
|
||||
export class FSecureFskImporter extends BaseImporter implements Importer {
|
||||
parse(data: string): Promise<ImportResult> {
|
||||
const result = new ImportResult();
|
||||
const results: FskFile = JSON.parse(data);
|
||||
if (results == null || results.data == null) {
|
||||
result.success = false;
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
for (const key in results.data) {
|
||||
// eslint-disable-next-line
|
||||
if (!results.data.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const value = results.data[key];
|
||||
const cipher = this.parseEntry(value);
|
||||
result.ciphers.push(cipher);
|
||||
}
|
||||
|
||||
result.success = true;
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
private parseEntry(entry: FskEntry): CipherView {
|
||||
const cipher = this.initLoginCipher();
|
||||
cipher.name = this.getValueOrDefault(entry.service);
|
||||
cipher.notes = this.getValueOrDefault(entry.notes);
|
||||
cipher.favorite = entry.favorite > 0;
|
||||
|
||||
switch (entry.type) {
|
||||
case FskEntryTypesEnum.Login:
|
||||
this.handleLoginEntry(entry, cipher);
|
||||
break;
|
||||
case FskEntryTypesEnum.CreditCard:
|
||||
this.handleCreditCardEntry(entry, cipher);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
this.convertToNoteIfNeeded(cipher);
|
||||
this.cleanupCipher(cipher);
|
||||
return cipher;
|
||||
}
|
||||
|
||||
private handleLoginEntry(entry: FskEntry, cipher: CipherView) {
|
||||
cipher.login.username = this.getValueOrDefault(entry.username);
|
||||
cipher.login.password = this.getValueOrDefault(entry.password);
|
||||
cipher.login.uris = this.makeUriArray(entry.url);
|
||||
}
|
||||
|
||||
private handleCreditCardEntry(entry: FskEntry, cipher: CipherView) {
|
||||
cipher.type = CipherType.Card;
|
||||
cipher.card = new CardView();
|
||||
cipher.card.cardholderName = this.getValueOrDefault(entry.username);
|
||||
cipher.card.number = this.getValueOrDefault(entry.creditNumber);
|
||||
cipher.card.brand = this.getCardBrand(cipher.card.number);
|
||||
cipher.card.code = this.getValueOrDefault(entry.creditCvv);
|
||||
if (!this.isNullOrWhitespace(entry.creditExpiry)) {
|
||||
if (!this.setCardExpiration(cipher, entry.creditExpiry)) {
|
||||
this.processKvp(cipher, "Expiration", entry.creditExpiry);
|
||||
}
|
||||
}
|
||||
if (!this.isNullOrWhitespace(entry.password)) {
|
||||
this.processKvp(cipher, "PIN", entry.password);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
export interface FskFile {
|
||||
data: Data;
|
||||
}
|
||||
|
||||
export interface Data {
|
||||
[key: string]: FskEntry;
|
||||
}
|
||||
|
||||
export enum FskEntryTypesEnum {
|
||||
Login = 1,
|
||||
CreditCard = 2,
|
||||
}
|
||||
|
||||
export interface FskEntry {
|
||||
color: string;
|
||||
creditCvv: string;
|
||||
creditExpiry: string;
|
||||
creditNumber: string;
|
||||
favorite: number; // UNIX timestamp
|
||||
notes: string;
|
||||
password: string;
|
||||
passwordList: PasswordList[];
|
||||
passwordModifiedDate: number; // UNIX timestamp
|
||||
rev: string | number;
|
||||
service: string;
|
||||
style: string;
|
||||
type: FskEntryTypesEnum;
|
||||
url: string;
|
||||
username: string;
|
||||
createdDate: number; // UNIX timestamp
|
||||
modifiedDate: number; // UNIX timestamp
|
||||
}
|
||||
|
||||
export interface PasswordList {
|
||||
changedate: string;
|
||||
password: string;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import { FskFile } from "./fsecure-fsk-types";
|
||||
|
||||
export const LoginTestEntry: FskFile = {
|
||||
data: {
|
||||
"1c3a2e31dcaa8459edd70a9d895ce298": {
|
||||
color: "#00A34D",
|
||||
createdDate: 0,
|
||||
creditCvv: "",
|
||||
creditExpiry: "",
|
||||
creditNumber: "",
|
||||
favorite: 1666440874,
|
||||
modifiedDate: 0,
|
||||
notes: "some note for example.com",
|
||||
password: "somePassword",
|
||||
passwordList: [],
|
||||
passwordModifiedDate: 0,
|
||||
rev: 1,
|
||||
service: "example.com",
|
||||
style: "website",
|
||||
type: 1,
|
||||
url: "https://www.example.com",
|
||||
username: "jdoe",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const CreditCardTestEntry: FskFile = {
|
||||
data: {
|
||||
"156498a46a3254f16035cbbbd09c2b8f": {
|
||||
color: "#00baff",
|
||||
createdDate: 1666438977,
|
||||
creditCvv: "123",
|
||||
creditExpiry: "22.10.2026",
|
||||
creditNumber: "4242424242424242",
|
||||
favorite: 0,
|
||||
modifiedDate: 1666438977,
|
||||
notes: "some notes to my card",
|
||||
password: "1234",
|
||||
passwordList: [],
|
||||
passwordModifiedDate: 1666438977,
|
||||
rev: 1,
|
||||
service: "My credit card",
|
||||
style: "creditcard",
|
||||
type: 2,
|
||||
url: "mybank",
|
||||
username: "John Doe",
|
||||
},
|
||||
},
|
||||
};
|
|
@ -31,7 +31,7 @@ import { EncryptrCsvImporter } from "../importers/encryptr-csv-importer";
|
|||
import { EnpassCsvImporter } from "../importers/enpass-csv-importer";
|
||||
import { EnpassJsonImporter } from "../importers/enpass-json-importer";
|
||||
import { FirefoxCsvImporter } from "../importers/firefox-csv-importer";
|
||||
import { FSecureFskImporter } from "../importers/fsecure-fsk-importer";
|
||||
import { FSecureFskImporter } from "../importers/fsecure/fsecure-fsk-importer";
|
||||
import { GnomeJsonImporter } from "../importers/gnome-json-importer";
|
||||
import { ImportError } from "../importers/import-error";
|
||||
import { Importer } from "../importers/importer";
|
||||
|
|
Loading…
Reference in New Issue