feat(ext/sw): export_backup handler

Reads vault state via GitHost, calls pack_backup_json in WASM, returns
the .relbak bytes back to the panel for chrome.downloads.download.
Reference image inclusion comes from chrome.storage.local.imageBase64.
Git history is never bundled from the extension (CLI is the source of
full backups).
This commit is contained in:
adlee-was-taken
2026-04-28 20:16:52 -04:00
parent f32c14f939
commit 5d9ea37b7f
2 changed files with 114 additions and 2 deletions

View File

@@ -383,8 +383,40 @@ export async function handle(
return { ok: true };
}
case 'export_backup':
return { ok: false, error: 'export_backup not yet implemented' };
case 'export_backup': {
if (!state.gitHost || !state.manifest) return { ok: false, error: 'vault_locked' };
try {
const blob = await vault.fetchVaultStateForBackup(state.gitHost, state.manifest);
let reference_jpg: string | null = null;
if (msg.includeImage) {
const stored = await chrome.storage.local.get('imageBase64');
const b64 = stored.imageBase64 as string | undefined;
if (!b64) return { ok: false, error: 'no reference image stored locally' };
reference_jpg = b64;
}
const inputJson = JSON.stringify({
salt: blob.salt_b64,
params_json: blob.params_json,
devices_json: blob.devices_json,
manifest_enc: blob.manifest_enc_b64,
settings_enc: blob.settings_enc_b64,
items: blob.items.map(i => ({ id: i.id, ciphertext: i.ciphertext_b64 })),
attachments: blob.attachments.map(a => ({
item_id: a.item_id, attachment_id: a.attachment_id, ciphertext: a.ciphertext_b64
})),
reference_jpg,
git_archive: null, // Extension never bundles git history.
});
const bytes: Uint8Array = state.wasm.pack_backup_json(inputJson, msg.passphrase);
return { ok: true, data: { bytes: bytes.buffer } };
} catch (e) {
return { ok: false, error: (e as Error).message };
}
}
case 'restore_backup':
return { ok: false, error: 'restore_backup not yet implemented' };