From 8b5deb0429f27262055a5443685cb5e55eadc0ca Mon Sep 17 00:00:00 2001 From: Justin <105444355+macronym@users.noreply.github.com> Date: Mon, 2 Sep 2024 18:10:01 -0400 Subject: [PATCH 1/2] Fix SecureSafe import fail (#10786) --- .../spec/securesafe-csv-importer.spec.ts | 27 ++++++++++++++++++- .../securesafe-csv/securesafe-example.csv.ts | 3 +++ .../src/importers/securesafe-csv-importer.ts | 22 +++++++++++++-- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/libs/importer/spec/securesafe-csv-importer.spec.ts b/libs/importer/spec/securesafe-csv-importer.spec.ts index 8d12ae12d942..f39d062002b7 100644 --- a/libs/importer/spec/securesafe-csv-importer.spec.ts +++ b/libs/importer/spec/securesafe-csv-importer.spec.ts @@ -4,7 +4,11 @@ import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; import { SecureSafeCsvImporter } from "../src/importers"; -import { data_upperUrl, data_lowerUrl } from "./test-data/securesafe-csv/securesafe-example.csv"; +import { + data_upperUrl, + data_lowerUrl, + data_surrounding_slashes, +} from "./test-data/securesafe-csv/securesafe-example.csv"; const CipherData = [ { @@ -49,6 +53,27 @@ const CipherData = [ type: 1, }), }, + { + title: "should remove surrounding slashes if present", + csv: data_surrounding_slashes, + expected: Object.assign(new CipherView(), { + id: null, + organizationId: null, + folderId: null, + name: "Gmail", + login: Object.assign(new LoginView(), { + username: "test@gmail.com", + password: "test", + uris: [ + Object.assign(new LoginUriView(), { + uri: "https://gmail.com", + }), + ], + }), + notes: "comment", + type: 1, + }), + }, ]; describe("SecureSafe CSV Importer", () => { diff --git a/libs/importer/spec/test-data/securesafe-csv/securesafe-example.csv.ts b/libs/importer/spec/test-data/securesafe-csv/securesafe-example.csv.ts index 75bf5127bf32..ea85e47045a3 100644 --- a/libs/importer/spec/test-data/securesafe-csv/securesafe-example.csv.ts +++ b/libs/importer/spec/test-data/securesafe-csv/securesafe-example.csv.ts @@ -3,3 +3,6 @@ export const data_upperUrl = `"Title","Username","Password","URL","Comment" export const data_lowerUrl = `"Title","Username","Password","url","Comment" "Gmail","test@gmail.com","test","https://gmail.com"`; + +export const data_surrounding_slashes = `"/Title/","/Username/","/Password/","/URL/","/Comment/", +"/Gmail/","/test@gmail.com/","/test/","/https://gmail.com/","/comment/"`; diff --git a/libs/importer/src/importers/securesafe-csv-importer.ts b/libs/importer/src/importers/securesafe-csv-importer.ts index 1664932cf5e4..f7d5a8fbd78a 100644 --- a/libs/importer/src/importers/securesafe-csv-importer.ts +++ b/libs/importer/src/importers/securesafe-csv-importer.ts @@ -12,9 +12,27 @@ export class SecureSafeCsvImporter extends BaseImporter implements Importer { return Promise.resolve(result); } + // SecureSafe currently exports CSV files with headers that are surrounded by slashes - 09/02/2024 + // This removes the slashes, if present. + const headers = Object.keys(results[0]); + const transformedHeaders = headers.map((header) => + header.startsWith("/") && header.endsWith("/") ? header.slice(1, -1) : header, + ); + const remappedResults = results.map((row) => { + const remappedRow: any = {}; + transformedHeaders.forEach((header, index) => { + let value = row[headers[index]]; + if (typeof value === "string" && value.startsWith("/") && value.endsWith("/")) { + value = value.slice(1, -1); + } + remappedRow[header] = value; + }); + return remappedRow; + }); + // The url field can be in different case formats. - const urlField = Object.keys(results[0]).find((k) => /url/i.test(k)); - results.forEach((value) => { + const urlField = Object.keys(remappedResults[0]).find((k) => /url/i.test(k)); + remappedResults.forEach((value) => { const cipher = this.initLoginCipher(); cipher.name = this.getValueOrDefault(value.Title); cipher.notes = this.getValueOrDefault(value.Comment); From e2e2a996406b03fbf2769ae887393bc216561481 Mon Sep 17 00:00:00 2001 From: Justin Brown <105444355+macronym@users.noreply.github.com> Date: Thu, 5 Sep 2024 02:53:52 -0400 Subject: [PATCH 2/2] Fix SecureSafe import fail * Replace headers with english form * Remove slashes surrounding the values if present * Added test --- libs/importer/spec/securesafe-csv-importer.spec.ts | 6 +++--- .../securesafe-csv/securesafe-example.csv.ts | 4 ++-- .../src/importers/securesafe-csv-importer.ts | 13 +++++++------ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/libs/importer/spec/securesafe-csv-importer.spec.ts b/libs/importer/spec/securesafe-csv-importer.spec.ts index f39d062002b7..2d91ad7fcea2 100644 --- a/libs/importer/spec/securesafe-csv-importer.spec.ts +++ b/libs/importer/spec/securesafe-csv-importer.spec.ts @@ -54,7 +54,7 @@ const CipherData = [ }), }, { - title: "should remove surrounding slashes if present", + title: "should change headers to english and remove surrounding slashes if present", csv: data_surrounding_slashes, expected: Object.assign(new CipherView(), { id: null, @@ -63,14 +63,14 @@ const CipherData = [ name: "Gmail", login: Object.assign(new LoginView(), { username: "test@gmail.com", - password: "test", + password: "/test", uris: [ Object.assign(new LoginUriView(), { uri: "https://gmail.com", }), ], }), - notes: "comment", + notes: "comment/", type: 1, }), }, diff --git a/libs/importer/spec/test-data/securesafe-csv/securesafe-example.csv.ts b/libs/importer/spec/test-data/securesafe-csv/securesafe-example.csv.ts index ea85e47045a3..c7e93f579560 100644 --- a/libs/importer/spec/test-data/securesafe-csv/securesafe-example.csv.ts +++ b/libs/importer/spec/test-data/securesafe-csv/securesafe-example.csv.ts @@ -4,5 +4,5 @@ export const data_upperUrl = `"Title","Username","Password","URL","Comment" export const data_lowerUrl = `"Title","Username","Password","url","Comment" "Gmail","test@gmail.com","test","https://gmail.com"`; -export const data_surrounding_slashes = `"/Title/","/Username/","/Password/","/URL/","/Comment/", -"/Gmail/","/test@gmail.com/","/test/","/https://gmail.com/","/comment/"`; +export const data_surrounding_slashes = `"/Titel/","/Benutzername/","/Passwort/","/URL/","/Kommentar/", +"/Gmail/","/test@gmail.com/","/test","/https://gmail.com/","comment/"`; diff --git a/libs/importer/src/importers/securesafe-csv-importer.ts b/libs/importer/src/importers/securesafe-csv-importer.ts index f7d5a8fbd78a..53f1460fde66 100644 --- a/libs/importer/src/importers/securesafe-csv-importer.ts +++ b/libs/importer/src/importers/securesafe-csv-importer.ts @@ -12,15 +12,16 @@ export class SecureSafeCsvImporter extends BaseImporter implements Importer { return Promise.resolve(result); } - // SecureSafe currently exports CSV files with headers that are surrounded by slashes - 09/02/2024 - // This removes the slashes, if present. + // SecureSafe currently exports values in multiple languages. - 09/05/2024 + // New headers are used to ensure import success. + const newHeaders = ["Title", "Username", "Password", "URL", "Comment"]; + + // SecureSafe can surround values in slashes. - 09/05/2024 + // This removes any surrounding slashes from the values. const headers = Object.keys(results[0]); - const transformedHeaders = headers.map((header) => - header.startsWith("/") && header.endsWith("/") ? header.slice(1, -1) : header, - ); const remappedResults = results.map((row) => { const remappedRow: any = {}; - transformedHeaders.forEach((header, index) => { + newHeaders.forEach((header, index) => { let value = row[headers[index]]; if (typeof value === "string" && value.startsWith("/") && value.endsWith("/")) { value = value.slice(1, -1);