mirror of
https://github.com/Blah-IM/Weblah.git
synced 2025-07-23 21:52:40 +00:00
feat: Add account export functionality for identity backup
This commit is contained in:
parent
e1d025470b
commit
4b51f2ebeb
4 changed files with 96 additions and 2 deletions
|
@ -5,7 +5,7 @@ import {
|
|||
type BlahProfile
|
||||
} from '@blah-im/core/identity';
|
||||
import { type IdentityDB, openIdentityDB } from './identityDB';
|
||||
import { BlahKeyPair } from '@blah-im/core/crypto';
|
||||
import { BlahKeyPair, type EncodedBlahKeyPair } from '@blah-im/core/crypto';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
export type Account = BlahIdentityDescription & {
|
||||
|
@ -106,6 +106,17 @@ class AccountManager {
|
|||
await this.loadAccounts();
|
||||
}
|
||||
|
||||
async exportAccountIDKeyPair(accountOrIdKeyId: Account | string): Promise<EncodedBlahKeyPair> {
|
||||
if (!this.keyDB) throw new Error('Account manager not initialized');
|
||||
|
||||
const idKeyId =
|
||||
typeof accountOrIdKeyId === 'string' ? accountOrIdKeyId : accountOrIdKeyId.id_key;
|
||||
const accountCreds = await this.keyDB.fetchAccount(idKeyId);
|
||||
const encodedIdKeyPair = accountCreds?.encodedIdKeyPair;
|
||||
if (!encodedIdKeyPair) throw new Error('No encoded ID key pair found');
|
||||
return encodedIdKeyPair;
|
||||
}
|
||||
|
||||
async changePassword(
|
||||
accountOrIdKeyId: Account | string,
|
||||
oldPassword: string,
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
import PageHeader from '$lib/components/PageHeader.svelte';
|
||||
import { DocumentDuplicate, Key } from 'svelte-hero-icons';
|
||||
import ChangePasswordDialog from './ChangePasswordDialog.svelte';
|
||||
import ExportIdentityKeyDialog from './ExportIdentityKeyDialog.svelte';
|
||||
|
||||
let showChangePasswordDialog = $state(false);
|
||||
let showExportIdentityDialog = $state(false);
|
||||
</script>
|
||||
|
||||
<PageHeader>
|
||||
|
@ -21,8 +23,16 @@
|
|||
</GroupedListSection>
|
||||
|
||||
<GroupedListSection>
|
||||
<GroupedListItem icon={DocumentDuplicate}>Backup Account</GroupedListItem>
|
||||
<GroupedListItem icon={DocumentDuplicate} onclick={() => (showExportIdentityDialog = true)}>Generate Identity Backup File</GroupedListItem>
|
||||
{#snippet footer()}
|
||||
<p>
|
||||
In case you don't have any other <em>full-access-enabled</em> devices, this file, combining
|
||||
with your <em>current password</em>, can be imported on Blah apps to regain
|
||||
<em>full access</em>.
|
||||
</p>
|
||||
{/snippet}
|
||||
</GroupedListSection>
|
||||
</GroupedListContainer>
|
||||
|
||||
<ChangePasswordDialog bind:open={showChangePasswordDialog} />
|
||||
<ExportIdentityKeyDialog bind:open={showExportIdentityDialog} />
|
||||
|
|
|
@ -190,6 +190,10 @@
|
|||
<p>
|
||||
Remember to change it on all other devices to which you granted <em>full access</em>.
|
||||
</p>
|
||||
<p>
|
||||
If you keeps backups of your identity, please update your backup file so it is encrypted
|
||||
with the new password.
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
</GroupedListContainer>
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<script lang="ts">
|
||||
import Button from '$lib/components/Button.svelte';
|
||||
import Dialog from '$lib/components/Dialog.svelte';
|
||||
import PageHeader from '$lib/components/PageHeader.svelte';
|
||||
import { accountManager } from '$lib/accounts';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
let { open = $bindable() }: Props = $props();
|
||||
|
||||
async function exportIdentityBackup() {
|
||||
try {
|
||||
if (!accountManager.currentAccountId || !accountManager.currentAccount) {
|
||||
throw new Error('No current account selected');
|
||||
}
|
||||
|
||||
const encodedKeyPair = await accountManager.exportAccountIDKeyPair(
|
||||
accountManager.currentAccountId
|
||||
);
|
||||
|
||||
// Create a JSON blob
|
||||
const jsonData = JSON.stringify(encodedKeyPair, null, 2);
|
||||
const blob = new Blob([jsonData], { type: 'application/json' });
|
||||
|
||||
// Generate download link
|
||||
const url = URL.createObjectURL(blob);
|
||||
const downloadLink = document.createElement('a');
|
||||
downloadLink.href = url;
|
||||
|
||||
// Set the filename with the account name
|
||||
const accountName =
|
||||
accountManager.currentAccount.profile?.signee.payload.name ||
|
||||
accountManager.currentAccountId.slice(-6);
|
||||
downloadLink.download = `Blah ID Backup - ${accountName}.json`;
|
||||
|
||||
// Trigger download and clean up
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
document.body.removeChild(downloadLink);
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
open = false;
|
||||
} catch (err) {
|
||||
console.error('Failed to export identity backup:', err);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog bind:open class="h-1/3">
|
||||
<PageHeader>
|
||||
<h3 class="grow">Export Identity Backup</h3>
|
||||
</PageHeader>
|
||||
|
||||
<div class="flex flex-col items-center space-y-6 overflow-y-auto p-6">
|
||||
<p class="text-center">
|
||||
This will generate a backup file containing your encrypted identity keys. You'll need your
|
||||
current password to use this backup later.
|
||||
</p>
|
||||
|
||||
<Button variant="primary" onclick={exportIdentityBackup}>Save Backup File</Button>
|
||||
|
||||
<p class="text-center text-sm text-gray-600">
|
||||
Keep this file in a secure location. Anyone with this file and your password will have
|
||||
<em>full access</em> to your account.
|
||||
</p>
|
||||
</div>
|
||||
</Dialog>
|
Loading…
Add table
Add a link
Reference in a new issue