1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-10-04 05:08:06 +02:00

Added capability on psono importer to add sub-folders (#7602)

This commit is contained in:
aj-rosado 2024-01-24 12:55:43 +00:00 committed by GitHub
parent 7436f9112d
commit 512f6ef892
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 146 additions and 6 deletions

View File

@ -11,6 +11,7 @@ import { FoldersTestData } from "./test-data/psono-json/folders";
import { GPGData } from "./test-data/psono-json/gpg";
import { NotesData } from "./test-data/psono-json/notes";
import { ReducedWebsiteLoginsData } from "./test-data/psono-json/reduced-website-logins";
import { SubFoldersTestData } from "./test-data/psono-json/subfolders";
import { TOTPData } from "./test-data/psono-json/totp";
import { WebsiteLoginsData } from "./test-data/psono-json/website-logins";
@ -37,6 +38,7 @@ describe("PSONO JSON Importer", () => {
const TOTPDataJson = JSON.stringify(TOTPData);
const EmptyTestFolderDataJson = JSON.stringify(EmptyTestFolderData);
const FoldersTestDataJson = JSON.stringify(FoldersTestData);
const SubFoldersTestDataJson = JSON.stringify(SubFoldersTestData);
const GPGDataJson = JSON.stringify(GPGData);
const EnvVariablesDataJson = JSON.stringify(EnvVariablesData);
const ReducedWebsiteLoginsDataJson = JSON.stringify(ReducedWebsiteLoginsData);
@ -245,4 +247,39 @@ describe("PSONO JSON Importer", () => {
expect(collections[0].name).toBe("TestFolder");
expect(collections[1].name).toBe("TestFolder2");
});
it("should create sub folders on folders with no items", async () => {
const importer = new PsonoJsonImporter();
const result = await importer.parse(SubFoldersTestDataJson);
expect(result != null).toBe(true);
const folders = result.folders;
expect(folders.length).toBe(4);
expect(folders[0].name).toBe("TestFolder/SubFolder1/SubSubFolder1");
expect(folders[1].name).toBe("TestFolder/SubFolder1");
expect(folders[2].name).toBe("TestFolder");
expect(folders[3].name).toBe("TestFolder2");
});
it("should assign entries to subfolders", async () => {
const importer = new PsonoJsonImporter();
const result = await importer.parse(SubFoldersTestDataJson);
expect(result != null).toBe(true);
const folders = result.folders;
const relationship1 = result.folderRelationships[0];
const relationship2 = result.folderRelationships[1];
const relationship3 = result.folderRelationships[2];
// // Check that ciphers have a folder assigned to them
expect(result.folderRelationships.length).toBe(result.ciphers.length);
expect(result.ciphers[relationship1[0]] == result.ciphers[0]);
expect(result.ciphers[relationship1[1]] == folders[0]);
expect(result.ciphers[relationship2[0]] == result.ciphers[1]);
expect(result.ciphers[relationship2[1]] == folders[2]);
expect(result.ciphers[relationship3[0]] == result.ciphers[2]);
expect(result.ciphers[relationship3[1]] == folders[3]);
});
});

View File

@ -0,0 +1,83 @@
import { PsonoJsonExport } from "../../../src/importers/psono/psono-json-types";
export const SubFoldersTestData: PsonoJsonExport = {
folders: [
{
name: "TestFolder",
folders: [
{
name: "SubFolder1",
folders: [
{
name: "SubSubFolder1",
items: [
{
type: "website_password",
name: "TestEntry on SubSubfolder",
autosubmit: true,
urlfilter: "filter",
website_password_title: "TestEntry on SubSubfolder",
website_password_url: "bitwarden.com",
website_password_username: "testUser",
website_password_password: "testPassword",
website_password_notes: "some notes",
website_password_auto_submit: true,
website_password_url_filter: "filter",
create_date: "2022-12-13T19:24:09.810266Z",
write_date: "2022-12-13T19:24:09.810292Z",
callback_url: "callback",
callback_user: "callbackUser",
callback_pass: "callbackPassword",
},
],
},
],
items: [
{
type: "website_password",
name: "TestEntry on Subfolder",
autosubmit: true,
urlfilter: "filter",
website_password_title: "TestEntry on Subfolder",
website_password_url: "bitwarden.com",
website_password_username: "testUser",
website_password_password: "testPassword",
website_password_notes: "some notes",
website_password_auto_submit: true,
website_password_url_filter: "filter",
create_date: "2022-12-13T19:24:09.810266Z",
write_date: "2022-12-13T19:24:09.810292Z",
callback_url: "callback",
callback_user: "callbackUser",
callback_pass: "callbackPassword",
},
],
},
],
},
{
name: "TestFolder2",
items: [
{
type: "website_password",
name: "TestEntry2",
autosubmit: true,
urlfilter: "filter",
website_password_title: "TestEntry2",
website_password_url: "bitwarden.com",
website_password_username: "testUser",
website_password_password: "testPassword",
website_password_notes: "some notes",
website_password_auto_submit: true,
website_password_url_filter: "filter",
create_date: "2022-12-13T19:24:09.810266Z",
write_date: "2022-12-13T19:24:09.810292Z",
callback_url: "callback",
callback_user: "callbackUser",
callback_pass: "callbackPassword",
},
],
},
],
items: [],
};

View File

@ -350,7 +350,11 @@ export abstract class BaseImporter {
}
}
protected processFolder(result: ImportResult, folderName: string) {
protected processFolder(
result: ImportResult,
folderName: string,
addRelationship: boolean = true,
) {
if (this.isNullOrWhitespace(folderName)) {
return;
}
@ -374,7 +378,10 @@ export abstract class BaseImporter {
result.folders.push(f);
}
result.folderRelationships.push([result.ciphers.length, folderIndex]);
//Some folders can have sub-folders but no ciphers directly, we should not add to the folderRelationships array
if (addRelationship) {
result.folderRelationships.push([result.ciphers.length, folderIndex]);
}
}
protected convertToNoteIfNeeded(cipher: CipherView) {

View File

@ -1,3 +1,4 @@
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { FieldType, SecureNoteType, CipherType } from "@bitwarden/common/vault/enums";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { SecureNoteView } from "@bitwarden/common/vault/models/view/secure-note.view";
@ -39,17 +40,28 @@ export class PsonoJsonImporter extends BaseImporter implements Importer {
return Promise.resolve(result);
}
private parseFolders(result: ImportResult, folders: FoldersEntity[]) {
private parseFolders(result: ImportResult, folders: FoldersEntity[], parentName?: string) {
if (folders == null || folders.length === 0) {
return;
}
folders.forEach((folder) => {
if (folder.items == null || folder.items.length == 0) {
const folderHasItems = folder.items != null && folder.items.length > 0;
const folderHasSubfolders = folder.folders != null && folder.folders.length > 0;
if (!folderHasItems && !folderHasSubfolders) {
return;
}
this.processFolder(result, folder.name);
if (!Utils.isNullOrWhitespace(parentName)) {
folder.name = parentName + "/" + folder.name;
}
if (folderHasSubfolders) {
this.parseFolders(result, folder.folders, folder.name);
}
this.processFolder(result, folder.name, folderHasItems);
this.handleItemParsing(result, folder.items);
});

View File

@ -14,7 +14,8 @@ export interface PsonoJsonExport {
export interface FoldersEntity {
name: string;
items: PsonoItemTypes[] | null;
items?: PsonoItemTypes[] | null;
folders?: FoldersEntity[] | null;
}
export interface RecordBase {