feat: add export and import functionality for Bitwarden and NodeWarden formats

- Implemented export formats for Bitwarden (JSON, encrypted JSON, ZIP) and NodeWarden (JSON).
- Added support for attachments in ciphers and introduced new types for handling attachments.
- Enhanced import formats to include Bitwarden ZIP and NodeWarden JSON.
- Updated internationalization strings for attachment-related features.
- Improved UI styles for attachment management and import summary display.
This commit is contained in:
shuaiplus
2026-03-04 01:03:49 +08:00
parent 7b4733d4c4
commit 819734ce5c
15 changed files with 2379 additions and 75 deletions
+12
View File
@@ -5,6 +5,8 @@ type ImportSourceEntry = { id: string; label: string };
export const IMPORT_SOURCES = [
{ id: 'bitwarden_json', label: 'Bitwarden (json)' },
{ id: 'bitwarden_csv', label: 'Bitwarden (csv)' },
{ id: 'bitwarden_zip', label: 'Bitwarden (zip)' },
{ id: 'nodewarden_json', label: 'NodeWarden (json)' },
{ id: 'onepassword_1pux', label: '1Password (1pux/json)' },
{ id: 'onepassword_1pif', label: '1Password (1pif)' },
{ id: 'onepassword_mac_csv', label: '1Password 6 and 7 Mac (csv)' },
@@ -53,8 +55,10 @@ export const IMPORT_SOURCES = [
export type ImportSourceId = (typeof IMPORT_SOURCES)[number]['id'];
export function getFileAcceptBySource(source: ImportSourceId): string {
if (source === 'bitwarden_zip') return '.zip,application/zip,application/x-zip-compressed';
if (
source === 'bitwarden_json' ||
source === 'nodewarden_json' ||
source === 'onepassword_1pux' ||
source === 'protonpass_json' ||
source === 'avast_json' ||
@@ -90,6 +94,7 @@ export interface BitwardenFieldInput {
linkedId?: number | null;
}
export interface BitwardenCipherInput {
id?: string | null;
type?: number | null;
name?: string | null;
notes?: string | null;
@@ -2415,6 +2420,7 @@ export function normalizeBitwardenImport(raw: unknown): CiphersImportPayload {
let hasAnyExplicitFolderLink = false;
for (const item of itemsRaw) {
ciphers.push({
id: item?.id ?? null,
type: Number(item?.type || 1) || 1,
name: item?.name ?? 'Untitled',
notes: item?.notes ?? null,
@@ -2498,6 +2504,12 @@ const IMPORT_SOURCE_PARSERS: Record<ImportSourceId, (textRaw: string) => Ciphers
bitwarden_json: () => {
throw new Error('bitwarden_json is handled by dedicated JSON flow');
},
bitwarden_zip: () => {
throw new Error('bitwarden_zip is handled by dedicated zip flow');
},
nodewarden_json: () => {
throw new Error('nodewarden_json is handled by dedicated JSON flow');
},
bitwarden_csv: parseBitwardenCsv,
onepassword_1pux: parseOnePassword1PuxJson,
onepassword_1pif: parseOnePassword1Pif,