mirror of
https://github.com/bitwarden/browser
synced 2025-12-11 22:03:36 +00:00
[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:
committed by
GitHub
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");
|
||||||
|
});
|
||||||
|
});
|
||||||
79
libs/common/src/importers/fsecure/fsecure-fsk-importer.ts
Normal file
79
libs/common/src/importers/fsecure/fsecure-fsk-importer.ts
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
libs/common/src/importers/fsecure/fsecure-fsk-types.ts
Normal file
37
libs/common/src/importers/fsecure/fsecure-fsk-types.ts
Normal file
@@ -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;
|
||||||
|
}
|
||||||
49
libs/common/src/importers/fsecure/fsk-test-data.ts
Normal file
49
libs/common/src/importers/fsecure/fsk-test-data.ts
Normal file
@@ -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 { EnpassCsvImporter } from "../importers/enpass-csv-importer";
|
||||||
import { EnpassJsonImporter } from "../importers/enpass-json-importer";
|
import { EnpassJsonImporter } from "../importers/enpass-json-importer";
|
||||||
import { FirefoxCsvImporter } from "../importers/firefox-csv-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 { GnomeJsonImporter } from "../importers/gnome-json-importer";
|
||||||
import { ImportError } from "../importers/import-error";
|
import { ImportError } from "../importers/import-error";
|
||||||
import { Importer } from "../importers/importer";
|
import { Importer } from "../importers/importer";
|
||||||
|
|||||||
Reference in New Issue
Block a user