mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 07:43:35 +00:00
[PS-2096] BEEEEP: Add Psono importer (#4286)
* Add psono json importer Create types for psono export format Add test files Write tests for psono-json-importer Write importer for psono export Register 'psonojson' with `importOptions` Import/register psono-json-importer with import.service Add instructions on how to export from Psono * Retain all imported data Ensure all data is retained by adding unmapped properties into custom fields Each item type has a set of mapped properties, anything not matching will be created as a custom field Write extensive tests to ensure data is present * Skipping GPG We currently cannot import GPG Keys into notes or custom fields * Add organizational test Verify that folders get converted to collections when imported by an org * Remove combined test-file (whole export) * Remove redundant null type
This commit is contained in:
committed by
GitHub
parent
651968ca9c
commit
b1a1068906
@@ -288,6 +288,10 @@
|
|||||||
From the Yoti browser extension, click on "Settings", then "Export Saved Logins" and save the
|
From the Yoti browser extension, click on "Settings", then "Export Saved Logins" and save the
|
||||||
CSV file.
|
CSV file.
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
<ng-container *ngIf="format === 'psonojson'">
|
||||||
|
Log in to the Psono web vault, click on the "Signed in as"-dropdown, select "Others". Go to
|
||||||
|
the "Export"-tab and select the json type export and then click on Export.
|
||||||
|
</ng-container>
|
||||||
<ng-container *ngIf="format === 'passkyjson'">
|
<ng-container *ngIf="format === 'passkyjson'">
|
||||||
Log in to "https://vault.passky.org" → "Import & Export" → "Export" in the Passky
|
Log in to "https://vault.passky.org" → "Import & Export" → "Export" in the Passky
|
||||||
section. ("Backup" is unsupported as it is encrypted).
|
section. ("Backup" is unsupported as it is encrypted).
|
||||||
|
|||||||
228
libs/common/spec/importers/psono-json-importer.spec.ts
Normal file
228
libs/common/spec/importers/psono-json-importer.spec.ts
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,20 @@
|
|||||||
|
import { PsonoJsonExport } from "@bitwarden/common/importers/psono/psono-json-types";
|
||||||
|
|
||||||
|
export const ApplicationPasswordsData: PsonoJsonExport = {
|
||||||
|
folders: [],
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: "application_password",
|
||||||
|
name: "My App Password",
|
||||||
|
application_password_title: "My App Password",
|
||||||
|
application_password_username: "someUser",
|
||||||
|
application_password_password: "somePassword",
|
||||||
|
application_password_notes: "some notes for the APP",
|
||||||
|
create_date: "2022-12-13T19:42:05.784077Z",
|
||||||
|
write_date: "2022-12-13T19:42:05.784103Z",
|
||||||
|
callback_url: "",
|
||||||
|
callback_user: "",
|
||||||
|
callback_pass: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { PsonoJsonExport } from "@bitwarden/common/importers/psono/psono-json-types";
|
||||||
|
|
||||||
|
export const BookmarkData: PsonoJsonExport = {
|
||||||
|
folders: [],
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: "bookmark",
|
||||||
|
name: "MyBookmark",
|
||||||
|
urlfilter: "bitwarden.com",
|
||||||
|
bookmark_title: "MyBookmark",
|
||||||
|
bookmark_url: "https://bitwarden.com",
|
||||||
|
bookmark_notes: "my notes for bitwarden.com",
|
||||||
|
bookmark_url_filter: "bitwarden.com",
|
||||||
|
create_date: "2022-12-13T19:39:26.631530Z",
|
||||||
|
write_date: "2022-12-13T19:39:26.631553Z",
|
||||||
|
callback_url: "",
|
||||||
|
callback_user: "",
|
||||||
|
callback_pass: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { PsonoJsonExport } from "@bitwarden/common/importers/psono/psono-json-types";
|
||||||
|
|
||||||
|
export const EmptyTestFolderData: PsonoJsonExport = {
|
||||||
|
folders: [
|
||||||
|
{
|
||||||
|
name: "EmptyFolder",
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { PsonoJsonExport } from "@bitwarden/common/importers/psono/psono-json-types";
|
||||||
|
|
||||||
|
export const EnvVariablesData: PsonoJsonExport = {
|
||||||
|
folders: [],
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: "environment_variables",
|
||||||
|
name: "My Environment Variables",
|
||||||
|
environment_variables_title: "My Environment Variables",
|
||||||
|
environment_variables_variables: [
|
||||||
|
{ key: "Key1", value: "Value1" },
|
||||||
|
{ key: "Key2", value: "Value2" },
|
||||||
|
],
|
||||||
|
environment_variables_notes: "Notes for environment variables",
|
||||||
|
create_date: "2022-12-13T19:41:02.028884Z",
|
||||||
|
write_date: "2022-12-13T19:41:02.028909Z",
|
||||||
|
callback_url: "",
|
||||||
|
callback_user: "",
|
||||||
|
callback_pass: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
53
libs/common/spec/importers/test-data/psono-json/folders.ts
Normal file
53
libs/common/spec/importers/test-data/psono-json/folders.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { PsonoJsonExport } from "@bitwarden/common/importers/psono/psono-json-types";
|
||||||
|
|
||||||
|
export const FoldersTestData: PsonoJsonExport = {
|
||||||
|
folders: [
|
||||||
|
{
|
||||||
|
name: "TestFolder",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: "website_password",
|
||||||
|
name: "TestEntry",
|
||||||
|
autosubmit: true,
|
||||||
|
urlfilter: "filter",
|
||||||
|
website_password_title: "TestEntry",
|
||||||
|
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: [],
|
||||||
|
};
|
||||||
23
libs/common/spec/importers/test-data/psono-json/gpg.ts
Normal file
23
libs/common/spec/importers/test-data/psono-json/gpg.ts
Normal file
File diff suppressed because one or more lines are too long
18
libs/common/spec/importers/test-data/psono-json/notes.ts
Normal file
18
libs/common/spec/importers/test-data/psono-json/notes.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { PsonoJsonExport } from "@bitwarden/common/importers/psono/psono-json-types";
|
||||||
|
|
||||||
|
export const NotesData: PsonoJsonExport = {
|
||||||
|
folders: [],
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: "note",
|
||||||
|
name: "My Note",
|
||||||
|
note_title: "My Note",
|
||||||
|
note_notes: "Notes for my Note",
|
||||||
|
create_date: "2022-12-13T19:41:18.770714Z",
|
||||||
|
write_date: "2022-12-13T19:41:18.770738Z",
|
||||||
|
callback_url: "",
|
||||||
|
callback_user: "",
|
||||||
|
callback_pass: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
22
libs/common/spec/importers/test-data/psono-json/totp.ts
Normal file
22
libs/common/spec/importers/test-data/psono-json/totp.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { PsonoJsonExport } from "@bitwarden/common/importers/psono/psono-json-types";
|
||||||
|
|
||||||
|
export const TOTPData: PsonoJsonExport = {
|
||||||
|
folders: [],
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: "totp",
|
||||||
|
name: "My TOTP",
|
||||||
|
totp_title: "My TOTP",
|
||||||
|
totp_period: 30,
|
||||||
|
totp_algorithm: "SHA1",
|
||||||
|
totp_digits: 6,
|
||||||
|
totp_code: "someSecretOfMine",
|
||||||
|
totp_notes: "Notes for TOTP",
|
||||||
|
create_date: "2022-12-13T19:41:42.972586Z",
|
||||||
|
write_date: "2022-12-13T19:41:42.972609Z",
|
||||||
|
callback_url: "",
|
||||||
|
callback_user: "",
|
||||||
|
callback_pass: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { PsonoJsonExport } from "@bitwarden/common/importers/psono/psono-json-types";
|
||||||
|
|
||||||
|
export const WebsiteLoginsData: PsonoJsonExport = {
|
||||||
|
folders: [],
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: "website_password",
|
||||||
|
name: "TestEntry",
|
||||||
|
autosubmit: true,
|
||||||
|
urlfilter: "filter",
|
||||||
|
website_password_title: "TestEntry",
|
||||||
|
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",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -67,6 +67,7 @@ export const regularImportOptions = [
|
|||||||
{ id: "encryptrcsv", name: "Encryptr (csv)" },
|
{ id: "encryptrcsv", name: "Encryptr (csv)" },
|
||||||
{ id: "yoticsv", name: "Yoti (csv)" },
|
{ id: "yoticsv", name: "Yoti (csv)" },
|
||||||
{ id: "nordpasscsv", name: "Nordpass (csv)" },
|
{ id: "nordpasscsv", name: "Nordpass (csv)" },
|
||||||
|
{ id: "psonojson", name: "Psono (json)" },
|
||||||
{ id: "passkyjson", name: "Passky (json)" },
|
{ id: "passkyjson", name: "Passky (json)" },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
|||||||
281
libs/common/src/importers/psono/psono-json-importer.ts
Normal file
281
libs/common/src/importers/psono/psono-json-importer.ts
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
import { CipherType } from "../../enums/cipherType";
|
||||||
|
import { FieldType } from "../../enums/fieldType";
|
||||||
|
import { SecureNoteType } from "../../enums/secureNoteType";
|
||||||
|
import { ImportResult } from "../../models/domain/import-result";
|
||||||
|
import { CipherView } from "../../models/view/cipher.view";
|
||||||
|
import { SecureNoteView } from "../../models/view/secure-note.view";
|
||||||
|
import { BaseImporter } from "../base-importer";
|
||||||
|
import { Importer } from "../importer";
|
||||||
|
|
||||||
|
import {
|
||||||
|
AppPasswordEntry,
|
||||||
|
BookmarkEntry,
|
||||||
|
EnvironmentVariablesEntry,
|
||||||
|
FoldersEntity,
|
||||||
|
GPGEntry,
|
||||||
|
NotesEntry,
|
||||||
|
PsonoItemTypes,
|
||||||
|
PsonoJsonExport,
|
||||||
|
TOTPEntry,
|
||||||
|
WebsitePasswordEntry,
|
||||||
|
} from "./psono-json-types";
|
||||||
|
|
||||||
|
export class PsonoJsonImporter extends BaseImporter implements Importer {
|
||||||
|
parse(data: string): Promise<ImportResult> {
|
||||||
|
const result = new ImportResult();
|
||||||
|
const psonoExport: PsonoJsonExport = JSON.parse(data);
|
||||||
|
if (psonoExport == null) {
|
||||||
|
result.success = false;
|
||||||
|
return Promise.resolve(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parseFolders(result, psonoExport.folders);
|
||||||
|
this.handleItemParsing(result, psonoExport.items);
|
||||||
|
|
||||||
|
if (this.organization) {
|
||||||
|
this.moveFoldersToCollections(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.success = true;
|
||||||
|
return Promise.resolve(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseFolders(result: ImportResult, folders: FoldersEntity[]) {
|
||||||
|
if (folders == null || folders.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
folders.forEach((folder) => {
|
||||||
|
if (folder.items == null || folder.items.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.processFolder(result, folder.name);
|
||||||
|
|
||||||
|
this.handleItemParsing(result, folder.items);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleItemParsing(result: ImportResult, items?: PsonoItemTypes[]) {
|
||||||
|
if (items == null || items.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
items.forEach((record) => {
|
||||||
|
const cipher = this.parsePsonoItem(record);
|
||||||
|
|
||||||
|
this.cleanupCipher(cipher);
|
||||||
|
result.ciphers.push(cipher);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private parsePsonoItem(item: PsonoItemTypes): CipherView {
|
||||||
|
const cipher = this.initLoginCipher();
|
||||||
|
|
||||||
|
switch (item.type) {
|
||||||
|
case "website_password":
|
||||||
|
this.parseWebsiteLogins(item, cipher);
|
||||||
|
break;
|
||||||
|
case "application_password":
|
||||||
|
this.parseApplicationPasswords(item, cipher);
|
||||||
|
break;
|
||||||
|
case "environment_variables":
|
||||||
|
this.parseEnvironmentVariables(item, cipher);
|
||||||
|
break;
|
||||||
|
case "totp":
|
||||||
|
this.parseTOTP(item, cipher);
|
||||||
|
break;
|
||||||
|
case "bookmark":
|
||||||
|
this.parseBookmarks(item, cipher);
|
||||||
|
break;
|
||||||
|
// Skipping this until we can save GPG into notes/custom fields
|
||||||
|
// case "mail_gpg_own_key":
|
||||||
|
// this.parseGPG(item, cipher);
|
||||||
|
// break;
|
||||||
|
case "note":
|
||||||
|
this.parseNotes(item, cipher);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cipher;
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly WEBSITE_mappedValues = new Set([
|
||||||
|
"type",
|
||||||
|
"name",
|
||||||
|
"website_password_title",
|
||||||
|
"website_password_notes",
|
||||||
|
"website_password_username",
|
||||||
|
"website_password_password",
|
||||||
|
"website_password_url",
|
||||||
|
"autosubmit",
|
||||||
|
"website_password_auto_submit",
|
||||||
|
"urlfilter",
|
||||||
|
"website_password_url_filter",
|
||||||
|
]);
|
||||||
|
private parseWebsiteLogins(entry: WebsitePasswordEntry, cipher: CipherView) {
|
||||||
|
if (entry == null || entry.type != "website_password") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cipher.name = entry.website_password_title;
|
||||||
|
cipher.notes = entry.website_password_notes;
|
||||||
|
|
||||||
|
cipher.login.username = entry.website_password_username;
|
||||||
|
cipher.login.password = entry.website_password_password;
|
||||||
|
|
||||||
|
cipher.login.uris = this.makeUriArray(entry.website_password_url);
|
||||||
|
|
||||||
|
this.processKvp(
|
||||||
|
cipher,
|
||||||
|
"website_password_auto_submit",
|
||||||
|
entry.website_password_auto_submit.toString(),
|
||||||
|
FieldType.Boolean
|
||||||
|
);
|
||||||
|
|
||||||
|
this.processKvp(cipher, "website_password_url_filter", entry.website_password_url_filter);
|
||||||
|
|
||||||
|
this.importUnmappedFields(cipher, entry, this.WEBSITE_mappedValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly APP_PWD_mappedValues = new Set([
|
||||||
|
"type",
|
||||||
|
"name",
|
||||||
|
"application_password_title",
|
||||||
|
"application_password_notes",
|
||||||
|
"application_password_username",
|
||||||
|
"application_password_password",
|
||||||
|
]);
|
||||||
|
private parseApplicationPasswords(entry: AppPasswordEntry, cipher: CipherView) {
|
||||||
|
if (entry == null || entry.type != "application_password") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cipher.name = entry.application_password_title;
|
||||||
|
cipher.notes = entry.application_password_notes;
|
||||||
|
|
||||||
|
cipher.login.username = entry.application_password_username;
|
||||||
|
cipher.login.password = entry.application_password_password;
|
||||||
|
|
||||||
|
this.importUnmappedFields(cipher, entry, this.APP_PWD_mappedValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly BOOKMARK_mappedValues = new Set([
|
||||||
|
"type",
|
||||||
|
"name",
|
||||||
|
"bookmark_title",
|
||||||
|
"bookmark_notes",
|
||||||
|
"bookmark_url",
|
||||||
|
]);
|
||||||
|
private parseBookmarks(entry: BookmarkEntry, cipher: CipherView) {
|
||||||
|
if (entry == null || entry.type != "bookmark") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cipher.name = entry.bookmark_title;
|
||||||
|
cipher.notes = entry.bookmark_notes;
|
||||||
|
|
||||||
|
cipher.login.uris = this.makeUriArray(entry.bookmark_url);
|
||||||
|
|
||||||
|
this.importUnmappedFields(cipher, entry, this.BOOKMARK_mappedValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly NOTES_mappedValues = new Set(["type", "name", "note_title", "note_notes"]);
|
||||||
|
private parseNotes(entry: NotesEntry, cipher: CipherView) {
|
||||||
|
if (entry == null || entry.type != "note") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cipher.type = CipherType.SecureNote;
|
||||||
|
cipher.secureNote = new SecureNoteView();
|
||||||
|
cipher.secureNote.type = SecureNoteType.Generic;
|
||||||
|
cipher.name = entry.note_title;
|
||||||
|
cipher.notes = entry.note_notes;
|
||||||
|
|
||||||
|
this.importUnmappedFields(cipher, entry, this.NOTES_mappedValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly TOTP_mappedValues = new Set(["type", "name", "totp_title", "totp_notes", "totp_code"]);
|
||||||
|
private parseTOTP(entry: TOTPEntry, cipher: CipherView) {
|
||||||
|
if (entry == null || entry.type != "totp") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cipher.name = entry.totp_title;
|
||||||
|
cipher.notes = entry.totp_notes;
|
||||||
|
|
||||||
|
cipher.login.totp = entry.totp_code;
|
||||||
|
|
||||||
|
this.importUnmappedFields(cipher, entry, this.TOTP_mappedValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly ENV_VARIABLES_mappedValues = new Set([
|
||||||
|
"type",
|
||||||
|
"name",
|
||||||
|
"environment_variables_title",
|
||||||
|
"environment_variables_notes",
|
||||||
|
"environment_variables_variables",
|
||||||
|
]);
|
||||||
|
private parseEnvironmentVariables(entry: EnvironmentVariablesEntry, cipher: CipherView) {
|
||||||
|
if (entry == null || entry.type != "environment_variables") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cipher.type = CipherType.SecureNote;
|
||||||
|
cipher.secureNote = new SecureNoteView();
|
||||||
|
cipher.secureNote.type = SecureNoteType.Generic;
|
||||||
|
cipher.name = entry.environment_variables_title;
|
||||||
|
cipher.notes = entry.environment_variables_notes;
|
||||||
|
|
||||||
|
entry.environment_variables_variables.forEach((KvPair) => {
|
||||||
|
this.processKvp(cipher, KvPair.key, KvPair.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.importUnmappedFields(cipher, entry, this.ENV_VARIABLES_mappedValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly GPG_mappedValues = new Set([
|
||||||
|
"type",
|
||||||
|
"name",
|
||||||
|
"mail_gpg_own_key_title",
|
||||||
|
"mail_gpg_own_key_public",
|
||||||
|
"mail_gpg_own_key_name",
|
||||||
|
"mail_gpg_own_key_email",
|
||||||
|
"mail_gpg_own_key_private",
|
||||||
|
]);
|
||||||
|
private parseGPG(entry: GPGEntry, cipher: CipherView) {
|
||||||
|
if (entry == null || entry.type != "mail_gpg_own_key") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cipher.type = CipherType.SecureNote;
|
||||||
|
cipher.secureNote = new SecureNoteView();
|
||||||
|
cipher.secureNote.type = SecureNoteType.Generic;
|
||||||
|
cipher.name = entry.mail_gpg_own_key_title;
|
||||||
|
cipher.notes = entry.mail_gpg_own_key_public;
|
||||||
|
|
||||||
|
this.processKvp(cipher, "mail_gpg_own_key_name", entry.mail_gpg_own_key_name);
|
||||||
|
this.processKvp(cipher, "mail_gpg_own_key_email", entry.mail_gpg_own_key_email);
|
||||||
|
this.processKvp(
|
||||||
|
cipher,
|
||||||
|
"mail_gpg_own_key_private",
|
||||||
|
entry.mail_gpg_own_key_private,
|
||||||
|
FieldType.Hidden
|
||||||
|
);
|
||||||
|
|
||||||
|
this.importUnmappedFields(cipher, entry, this.GPG_mappedValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
private importUnmappedFields(
|
||||||
|
cipher: CipherView,
|
||||||
|
entry: PsonoItemTypes,
|
||||||
|
mappedValues: Set<string>
|
||||||
|
) {
|
||||||
|
const unmappedFields = Object.keys(entry).filter((x) => !mappedValues.has(x));
|
||||||
|
unmappedFields.forEach((key) => {
|
||||||
|
const item = entry as any;
|
||||||
|
this.processKvp(cipher, key, item[key].toString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
109
libs/common/src/importers/psono/psono-json-types.ts
Normal file
109
libs/common/src/importers/psono/psono-json-types.ts
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
export type PsonoItemTypes =
|
||||||
|
| WebsitePasswordEntry
|
||||||
|
| AppPasswordEntry
|
||||||
|
| TOTPEntry
|
||||||
|
| NotesEntry
|
||||||
|
| EnvironmentVariablesEntry
|
||||||
|
| GPGEntry
|
||||||
|
| BookmarkEntry;
|
||||||
|
|
||||||
|
export interface PsonoJsonExport {
|
||||||
|
folders?: FoldersEntity[];
|
||||||
|
items?: PsonoItemTypes[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FoldersEntity {
|
||||||
|
name: string;
|
||||||
|
items: PsonoItemTypes[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RecordBase {
|
||||||
|
type: PsonoEntryTypes;
|
||||||
|
name: string;
|
||||||
|
create_date: string;
|
||||||
|
write_date: string;
|
||||||
|
callback_url: string;
|
||||||
|
callback_user: string;
|
||||||
|
callback_pass: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PsonoEntryTypes =
|
||||||
|
| "website_password"
|
||||||
|
| "bookmark"
|
||||||
|
| "mail_gpg_own_key"
|
||||||
|
| "environment_variables"
|
||||||
|
| "note"
|
||||||
|
| "application_password"
|
||||||
|
| "totp";
|
||||||
|
|
||||||
|
export interface WebsitePasswordEntry extends RecordBase {
|
||||||
|
type: "website_password";
|
||||||
|
autosubmit: boolean;
|
||||||
|
urlfilter: string;
|
||||||
|
website_password_title: string;
|
||||||
|
website_password_url: string;
|
||||||
|
website_password_username: string;
|
||||||
|
website_password_password: string;
|
||||||
|
website_password_notes: string;
|
||||||
|
website_password_auto_submit: boolean;
|
||||||
|
website_password_url_filter: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PsonoEntry {
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BookmarkEntry extends RecordBase {
|
||||||
|
type: "bookmark";
|
||||||
|
urlfilter: string;
|
||||||
|
bookmark_title: string;
|
||||||
|
bookmark_url: string;
|
||||||
|
bookmark_notes: string;
|
||||||
|
bookmark_url_filter: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GPGEntry extends RecordBase {
|
||||||
|
type: "mail_gpg_own_key";
|
||||||
|
mail_gpg_own_key_title: string;
|
||||||
|
mail_gpg_own_key_email: string;
|
||||||
|
mail_gpg_own_key_name: string;
|
||||||
|
mail_gpg_own_key_public: string;
|
||||||
|
mail_gpg_own_key_private: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EnvironmentVariablesEntry extends RecordBase {
|
||||||
|
type: "environment_variables";
|
||||||
|
environment_variables_title: string;
|
||||||
|
environment_variables_variables: EnvironmentVariables_KVPair[];
|
||||||
|
environment_variables_notes: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EnvironmentVariables_KVPair {
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AppPasswordEntry extends RecordBase {
|
||||||
|
type: "application_password";
|
||||||
|
application_password_title: string;
|
||||||
|
application_password_username: string;
|
||||||
|
application_password_password: string;
|
||||||
|
application_password_notes: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TOTPEntry extends RecordBase {
|
||||||
|
type: "totp";
|
||||||
|
totp_title: string;
|
||||||
|
totp_period: number;
|
||||||
|
totp_algorithm: "SHA1";
|
||||||
|
totp_digits: number;
|
||||||
|
totp_code: string;
|
||||||
|
totp_notes: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NotesEntry extends RecordBase {
|
||||||
|
type: "note";
|
||||||
|
note_title: string;
|
||||||
|
note_notes: string;
|
||||||
|
}
|
||||||
@@ -59,6 +59,7 @@ import { PasswordBossJsonImporter } from "../importers/passwordboss-json-importe
|
|||||||
import { PasswordDragonXmlImporter } from "../importers/passworddragon-xml-importer";
|
import { PasswordDragonXmlImporter } from "../importers/passworddragon-xml-importer";
|
||||||
import { PasswordSafeXmlImporter } from "../importers/passwordsafe-xml-importer";
|
import { PasswordSafeXmlImporter } from "../importers/passwordsafe-xml-importer";
|
||||||
import { PasswordWalletTxtImporter } from "../importers/passwordwallet-txt-importer";
|
import { PasswordWalletTxtImporter } from "../importers/passwordwallet-txt-importer";
|
||||||
|
import { PsonoJsonImporter } from "../importers/psono/psono-json-importer";
|
||||||
import { RememBearCsvImporter } from "../importers/remembear-csv-importer";
|
import { RememBearCsvImporter } from "../importers/remembear-csv-importer";
|
||||||
import { RoboFormCsvImporter } from "../importers/roboform-csv-importer";
|
import { RoboFormCsvImporter } from "../importers/roboform-csv-importer";
|
||||||
import { SafariCsvImporter } from "../importers/safari-csv-importer";
|
import { SafariCsvImporter } from "../importers/safari-csv-importer";
|
||||||
@@ -280,6 +281,8 @@ export class ImportService implements ImportServiceAbstraction {
|
|||||||
return new YotiCsvImporter();
|
return new YotiCsvImporter();
|
||||||
case "nordpasscsv":
|
case "nordpasscsv":
|
||||||
return new NordPassCsvImporter();
|
return new NordPassCsvImporter();
|
||||||
|
case "psonojson":
|
||||||
|
return new PsonoJsonImporter();
|
||||||
case "passkyjson":
|
case "passkyjson":
|
||||||
return new PasskyJsonImporter();
|
return new PasskyJsonImporter();
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user