mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[PM-18153] add support for importing some older / wonky card formats from msecure (#13328)
* add support for importing some older / wonky card formats from msecure * slightly less fuzzy logic --------- Co-authored-by: Daniel James Smith <2670567+djsmith85@users.noreply.github.com>
This commit is contained in:
@@ -8,6 +8,24 @@ describe("MSecureCsvImporter.parse", () => {
|
||||
importer = new MSecureCsvImporter();
|
||||
});
|
||||
|
||||
it("should correctly parse legacy formatted cards", async () => {
|
||||
const mockCsvData =
|
||||
`aWeirdOldStyleCard|1032,Credit Card,,Security code 1234,Card Number|12|5555 4444 3333 2222,Expiration Date|11|04/0029,Name on Card|9|Obi Wan Kenobi,Security Code|9|444,`.trim();
|
||||
const result = await importer.parse(mockCsvData);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.ciphers.length).toBe(1);
|
||||
const cipher = result.ciphers[0];
|
||||
expect(cipher.name).toBe("aWeirdOldStyleCard");
|
||||
expect(cipher.type).toBe(CipherType.Card);
|
||||
expect(cipher.card.number).toBe("5555 4444 3333 2222");
|
||||
expect(cipher.card.expiration).toBe("04 / 2029");
|
||||
expect(cipher.card.code).toBe("444");
|
||||
expect(cipher.card.cardholderName).toBe("Obi Wan Kenobi");
|
||||
expect(cipher.notes).toBe("Security code 1234");
|
||||
expect(cipher.card.brand).toBe("");
|
||||
});
|
||||
|
||||
it("should correctly parse credit card entries as Secret Notes", async () => {
|
||||
const mockCsvData =
|
||||
`myCreditCard|155089404,Credit Card,,,Card Number|12|41111111111111111,Expiration Date|11|05/2026,Security Code|9|123,Name on Card|0|John Doe,PIN|9|1234,Issuing Bank|0|Visa,Phone Number|4|,Billing Address|0|,`.trim();
|
||||
|
||||
@@ -43,23 +43,34 @@ export class MSecureCsvImporter extends BaseImporter implements Importer {
|
||||
).split("/");
|
||||
cipher.card.expMonth = month.trim();
|
||||
cipher.card.expYear = year.trim();
|
||||
cipher.card.code = this.getValueOrDefault(this.splitValueRetainingLastPart(value[6]));
|
||||
cipher.card.cardholderName = this.getValueOrDefault(
|
||||
this.splitValueRetainingLastPart(value[7]),
|
||||
const securityCodeRegex = RegExp("^Security Code\\|\\d*\\|");
|
||||
const securityCodeEntry = value.find((entry: string) => securityCodeRegex.test(entry));
|
||||
cipher.card.code = this.getValueOrDefault(
|
||||
this.splitValueRetainingLastPart(securityCodeEntry),
|
||||
);
|
||||
cipher.card.brand = this.getValueOrDefault(this.splitValueRetainingLastPart(value[9]));
|
||||
cipher.notes =
|
||||
this.getValueOrDefault(value[8].split("|")[0]) +
|
||||
": " +
|
||||
this.getValueOrDefault(this.splitValueRetainingLastPart(value[8]), "") +
|
||||
"\n" +
|
||||
this.getValueOrDefault(value[10].split("|")[0]) +
|
||||
": " +
|
||||
this.getValueOrDefault(this.splitValueRetainingLastPart(value[10]), "") +
|
||||
"\n" +
|
||||
this.getValueOrDefault(value[11].split("|")[0]) +
|
||||
": " +
|
||||
this.getValueOrDefault(this.splitValueRetainingLastPart(value[11]), "");
|
||||
|
||||
const cardNameRegex = RegExp("^Name on Card\\|\\d*\\|");
|
||||
const nameOnCardEntry = value.find((entry: string) => entry.match(cardNameRegex));
|
||||
cipher.card.cardholderName = this.getValueOrDefault(
|
||||
this.splitValueRetainingLastPart(nameOnCardEntry),
|
||||
);
|
||||
|
||||
cipher.card.brand = this.getValueOrDefault(this.splitValueRetainingLastPart(value[9]), "");
|
||||
|
||||
const noteRegex = RegExp("\\|\\d*\\|");
|
||||
const rawNotes = value
|
||||
.slice(2)
|
||||
.filter((entry: string) => !this.isNullOrWhitespace(entry) && !noteRegex.test(entry));
|
||||
const noteIndexes = [8, 10, 11];
|
||||
const indexedNotes = noteIndexes
|
||||
.filter((idx) => value[idx] && noteRegex.test(value[idx]))
|
||||
.map((idx) => value[idx])
|
||||
.map((val) => {
|
||||
const key = val.split("|")[0];
|
||||
const value = this.getValueOrDefault(this.splitValueRetainingLastPart(val), "");
|
||||
return `${key}: ${value}`;
|
||||
});
|
||||
cipher.notes = [...rawNotes, ...indexedNotes].join("\n");
|
||||
} else if (value.length > 3) {
|
||||
cipher.type = CipherType.SecureNote;
|
||||
cipher.secureNote = new SecureNoteView();
|
||||
@@ -95,6 +106,6 @@ export class MSecureCsvImporter extends BaseImporter implements Importer {
|
||||
// like "Password|8|myPassword", we want to keep the "myPassword" but also ensure that if
|
||||
// the value contains any "|" it works fine
|
||||
private splitValueRetainingLastPart(value: string) {
|
||||
return value.split("|").slice(0, 2).concat(value.split("|").slice(2).join("|")).pop();
|
||||
return value && value.split("|").slice(0, 2).concat(value.split("|").slice(2).join("|")).pop();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user