1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 00:33:44 +00:00

[PM-15483] PasswordXP-CSV-Importer: Add support for German and Dutch headers (#12216)

* Add tests to verify importing German and Dutch headers work

* Add method to translate the headers from (German/Dutch into English) while the CSV data is being parsed

* Report "importFormatError" when header translation did not work, instead of a generic undefined error (startsWith)

* Move passwordxp-csv-importer into a dedicated folder

* Introduce files with the language header translations

---------

Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
This commit is contained in:
Daniel James Smith
2024-12-17 20:51:58 +01:00
committed by GitHub
parent d1fe72a4ab
commit e2e9a7c345
7 changed files with 117 additions and 39 deletions

View File

@@ -45,7 +45,7 @@ export { PasswordBossJsonImporter } from "./passwordboss-json-importer";
export { PasswordDragonXmlImporter } from "./passworddragon-xml-importer";
export { PasswordSafeXmlImporter } from "./passwordsafe-xml-importer";
export { PasswordWalletTxtImporter } from "./passwordwallet-txt-importer";
export { PasswordXPCsvImporter } from "./passwordxp-csv-importer";
export { PasswordXPCsvImporter } from "./passsordxp/passwordxp-csv-importer";
export { ProtonPassJsonImporter } from "./protonpass/protonpass-json-importer";
export { PsonoJsonImporter } from "./psono/psono-json-importer";
export { RememBearCsvImporter } from "./remembear-csv-importer";

View File

@@ -0,0 +1,10 @@
export const dutchHeaderTranslations: { [key: string]: string } = {
Titel: "Title",
Gebruikersnaam: "Username",
Wachtwoord: "Password",
Gewijzigd: "Modified",
Gemaakt: "Created",
"Verloopt op": "Expire on",
Beschrijving: "Description",
"Gewijzigd door": "Modified by",
};

View File

@@ -0,0 +1,11 @@
export const germanHeaderTranslations: { [key: string]: string } = {
Titel: "Title",
Benutzername: "Username",
Konto: "Account",
Passwort: "Password",
"Geändert am": "Modified",
"Erstellt am": "Created",
"Läuft ab am": "Expire on",
Beschreibung: "Description",
"Geändert von": "Modified by",
};

View File

@@ -1,12 +1,28 @@
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { ImportResult } from "../models/import-result";
import { BaseImporter } from "./base-importer";
import { Importer } from "./importer";
import { ImportResult } from "../../models/import-result";
import { BaseImporter } from "../base-importer";
import { Importer } from "../importer";
const _mappedColumns = new Set(["Title", "Username", "URL", "Password", "Description"]);
import { dutchHeaderTranslations } from "./dutch-csv-headers";
import { germanHeaderTranslations } from "./german-csv-headers";
/* Translates the headers from non-English to English
* This is necessary because the parser only maps English headers to ciphers
* Currently only supports German and Dutch translations
*/
function translateIntoEnglishHeaders(header: string): string {
const translations: { [key: string]: string } = {
// The header column 'User name' is parsed by the parser, but cannot be used as a variable. This converts it to a valid variable name, prior to parsing.
"User name": "Username",
...germanHeaderTranslations,
...dutchHeaderTranslations,
};
return translations[header] || header;
}
/**
* PasswordXP CSV importer
@@ -17,15 +33,22 @@ export class PasswordXPCsvImporter extends BaseImporter implements Importer {
* @param data
*/
parse(data: string): Promise<ImportResult> {
// The header column 'User name' is parsed by the parser, but cannot be used as a variable. This converts it to a valid variable name, prior to parsing.
data = data.replace(";User name;", ";Username;");
const result = new ImportResult();
const results = this.parseCsv(data, true, { skipEmptyLines: true });
const results = this.parseCsv(data, true, {
skipEmptyLines: true,
transformHeader: translateIntoEnglishHeaders,
});
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
// If the first row (header check) does not contain the column "Title", then the data is invalid (no translation found)
if (!results[0].Title) {
result.success = false;
return Promise.resolve(result);
}
let currentFolderName = "";
results.forEach((row) => {
// Skip rows starting with '>>>' as they indicate items following have no folder assigned to them