mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-30 22:41:33 +01:00
Add passky importer (#4253)
Create types for passky export format Add test files Write tests for passky-json-importer Write importer for passky export Register 'passkyjson' with `importOptions` Import/register passky-json-importer with import.service Add instructions on how to export from Passky
This commit is contained in:
parent
f67fffcc08
commit
8c8d4b3e3e
@ -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 === 'passkyjson'">
|
||||||
|
Log in to "https://vault.passky.org" → "Import & Export" → "Export" in the Passky
|
||||||
|
section. ("Backup" is unsupported as it is encrypted).
|
||||||
|
</ng-container>
|
||||||
</app-callout>
|
</app-callout>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
|
34
libs/common/spec/importers/passky-json-importer.spec.ts
Normal file
34
libs/common/spec/importers/passky-json-importer.spec.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { PasskyJsonImporter as Importer } from "@bitwarden/common/importers/passky/passky-json-importer";
|
||||||
|
|
||||||
|
import { testData as EncryptedData } from "./test-data/passky-json/passky-encrypted.json";
|
||||||
|
import { testData as UnencryptedData } from "./test-data/passky-json/passky-unencrypted.json";
|
||||||
|
|
||||||
|
describe("Passky Json Importer", () => {
|
||||||
|
let importer: Importer;
|
||||||
|
beforeEach(() => {
|
||||||
|
importer = new Importer();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not import encrypted backups", async () => {
|
||||||
|
const testDataJson = JSON.stringify(EncryptedData);
|
||||||
|
const result = await importer.parse(testDataJson);
|
||||||
|
expect(result != null).toBe(true);
|
||||||
|
expect(result.success).toBe(false);
|
||||||
|
expect(result.errorMessage).toBe("Unable to import an encrypted passky backup.");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should parse login data", async () => {
|
||||||
|
const testDataJson = JSON.stringify(UnencryptedData);
|
||||||
|
const result = await importer.parse(testDataJson);
|
||||||
|
expect(result != null).toBe(true);
|
||||||
|
|
||||||
|
const cipher = result.ciphers.shift();
|
||||||
|
expect(cipher.name).toEqual("https://bitwarden.com/");
|
||||||
|
expect(cipher.login.username).toEqual("testUser");
|
||||||
|
expect(cipher.login.password).toEqual("testPassword");
|
||||||
|
expect(cipher.login.uris.length).toEqual(1);
|
||||||
|
const uriView = cipher.login.uris.shift();
|
||||||
|
expect(uriView.uri).toEqual("https://bitwarden.com/");
|
||||||
|
expect(cipher.notes).toEqual("my notes");
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,15 @@
|
|||||||
|
import { PasskyJsonExport } from "@bitwarden/common/importers/passky/passky-json-types";
|
||||||
|
|
||||||
|
export const testData: PasskyJsonExport = {
|
||||||
|
encrypted: true,
|
||||||
|
passwords: [
|
||||||
|
{
|
||||||
|
website:
|
||||||
|
"w68uw6nCjUI3w7MNYsK7w6xqwqHDlXLCpsOEw4/Dq8KbIMK3w6fCvQJFFcOECsOlwprCqUAawqnDvsKbwrLCsCXCtcOlw4dp",
|
||||||
|
username: "bMKyUC0VPTx5woHCr8K9wpvDgGrClFAKw6VfJTgob8KVwqNoN8KIEA==",
|
||||||
|
password: "XcKxO2FjwqIJPkoHwqrDvcKtXcORw6TDlMOlw7TDvMORfmlNdMKOwq7DocO+",
|
||||||
|
message:
|
||||||
|
"w5jCrWTCgAV1RcO+DsOzw5zCvD5CwqLCtcKtw6sPwpbCmcOxwrfDlcOQw4h1wqomEhNtUkRgwrzCkxrClFBSHsO5wrfCrg==",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
@ -0,0 +1,13 @@
|
|||||||
|
import { PasskyJsonExport } from "@bitwarden/common/importers/passky/passky-json-types";
|
||||||
|
|
||||||
|
export const testData: PasskyJsonExport = {
|
||||||
|
encrypted: false,
|
||||||
|
passwords: [
|
||||||
|
{
|
||||||
|
website: "https://bitwarden.com/",
|
||||||
|
username: "testUser",
|
||||||
|
password: "testPassword",
|
||||||
|
message: "my notes",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
@ -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: "passkyjson", name: "Passky (json)" },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type ImportType =
|
export type ImportType =
|
||||||
|
43
libs/common/src/importers/passky/passky-json-importer.ts
Normal file
43
libs/common/src/importers/passky/passky-json-importer.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { ImportResult } from "../../models/domain/import-result";
|
||||||
|
import { BaseImporter } from "../base-importer";
|
||||||
|
import { Importer } from "../importer";
|
||||||
|
|
||||||
|
import { PasskyJsonExport } from "./passky-json-types";
|
||||||
|
|
||||||
|
export class PasskyJsonImporter extends BaseImporter implements Importer {
|
||||||
|
parse(data: string): Promise<ImportResult> {
|
||||||
|
const result = new ImportResult();
|
||||||
|
const passkyExport: PasskyJsonExport = JSON.parse(data);
|
||||||
|
if (
|
||||||
|
passkyExport == null ||
|
||||||
|
passkyExport.passwords == null ||
|
||||||
|
passkyExport.passwords.length === 0
|
||||||
|
) {
|
||||||
|
result.success = false;
|
||||||
|
return Promise.resolve(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (passkyExport.encrypted == true) {
|
||||||
|
result.success = false;
|
||||||
|
result.errorMessage = "Unable to import an encrypted passky backup.";
|
||||||
|
return Promise.resolve(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
passkyExport.passwords.forEach((record) => {
|
||||||
|
const cipher = this.initLoginCipher();
|
||||||
|
cipher.name = record.website;
|
||||||
|
cipher.login.username = record.username;
|
||||||
|
cipher.login.password = record.password;
|
||||||
|
|
||||||
|
cipher.login.uris = this.makeUriArray(record.website);
|
||||||
|
cipher.notes = record.message;
|
||||||
|
|
||||||
|
this.convertToNoteIfNeeded(cipher);
|
||||||
|
this.cleanupCipher(cipher);
|
||||||
|
result.ciphers.push(cipher);
|
||||||
|
});
|
||||||
|
|
||||||
|
result.success = true;
|
||||||
|
return Promise.resolve(result);
|
||||||
|
}
|
||||||
|
}
|
11
libs/common/src/importers/passky/passky-json-types.ts
Normal file
11
libs/common/src/importers/passky/passky-json-types.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export interface PasskyJsonExport {
|
||||||
|
encrypted: boolean;
|
||||||
|
passwords: LoginEntry[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginEntry {
|
||||||
|
website: string;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
message: string;
|
||||||
|
}
|
@ -51,6 +51,7 @@ import { OnePasswordMacCsvImporter } from "../importers/onepassword/onepassword-
|
|||||||
import { OnePasswordWinCsvImporter } from "../importers/onepassword/onepassword-win-csv-importer";
|
import { OnePasswordWinCsvImporter } from "../importers/onepassword/onepassword-win-csv-importer";
|
||||||
import { PadlockCsvImporter } from "../importers/padlock-csv-importer";
|
import { PadlockCsvImporter } from "../importers/padlock-csv-importer";
|
||||||
import { PassKeepCsvImporter } from "../importers/passkeep-csv-importer";
|
import { PassKeepCsvImporter } from "../importers/passkeep-csv-importer";
|
||||||
|
import { PasskyJsonImporter } from "../importers/passky/passky-json-importer";
|
||||||
import { PassmanJsonImporter } from "../importers/passman-json-importer";
|
import { PassmanJsonImporter } from "../importers/passman-json-importer";
|
||||||
import { PasspackCsvImporter } from "../importers/passpack-csv-importer";
|
import { PasspackCsvImporter } from "../importers/passpack-csv-importer";
|
||||||
import { PasswordAgentCsvImporter } from "../importers/passwordagent-csv-importer";
|
import { PasswordAgentCsvImporter } from "../importers/passwordagent-csv-importer";
|
||||||
@ -279,6 +280,8 @@ export class ImportService implements ImportServiceAbstraction {
|
|||||||
return new YotiCsvImporter();
|
return new YotiCsvImporter();
|
||||||
case "nordpasscsv":
|
case "nordpasscsv":
|
||||||
return new NordPassCsvImporter();
|
return new NordPassCsvImporter();
|
||||||
|
case "passkyjson":
|
||||||
|
return new PasskyJsonImporter();
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user