1
0
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:
Daniel James Smith 2022-12-19 21:47:45 +01:00 committed by GitHub
parent f67fffcc08
commit 8c8d4b3e3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 124 additions and 0 deletions

View File

@ -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" &rarr; "Import & Export" &rarr; "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">

View 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");
});
});

View File

@ -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==",
},
],
};

View File

@ -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",
},
],
};

View File

@ -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 =

View 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);
}
}

View File

@ -0,0 +1,11 @@
export interface PasskyJsonExport {
encrypted: boolean;
passwords: LoginEntry[];
}
export interface LoginEntry {
website: string;
username: string;
password: string;
message: string;
}

View File

@ -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;
} }