mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-22 11:45:59 +01: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:
parent
651968ca9c
commit
b1a1068906
@ -288,6 +288,10 @@
|
||||
From the Yoti browser extension, click on "Settings", then "Export Saved Logins" and save the
|
||||
CSV file.
|
||||
</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'">
|
||||
Log in to "https://vault.passky.org" → "Import & Export" → "Export" in the Passky
|
||||
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: "yoticsv", name: "Yoti (csv)" },
|
||||
{ id: "nordpasscsv", name: "Nordpass (csv)" },
|
||||
{ id: "psonojson", name: "Psono (json)" },
|
||||
{ id: "passkyjson", name: "Passky (json)" },
|
||||
] 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 { PasswordSafeXmlImporter } from "../importers/passwordsafe-xml-importer";
|
||||
import { PasswordWalletTxtImporter } from "../importers/passwordwallet-txt-importer";
|
||||
import { PsonoJsonImporter } from "../importers/psono/psono-json-importer";
|
||||
import { RememBearCsvImporter } from "../importers/remembear-csv-importer";
|
||||
import { RoboFormCsvImporter } from "../importers/roboform-csv-importer";
|
||||
import { SafariCsvImporter } from "../importers/safari-csv-importer";
|
||||
@ -280,6 +281,8 @@ export class ImportService implements ImportServiceAbstraction {
|
||||
return new YotiCsvImporter();
|
||||
case "nordpasscsv":
|
||||
return new NordPassCsvImporter();
|
||||
case "psonojson":
|
||||
return new PsonoJsonImporter();
|
||||
case "passkyjson":
|
||||
return new PasskyJsonImporter();
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user