mirror of
https://github.com/Blah-IM/Weblah.git
synced 2025-07-28 08:02:38 +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
|
type BlahProfile
|
||||||
} from '@blah-im/core/identity';
|
} from '@blah-im/core/identity';
|
||||||
import { type IdentityDB, openIdentityDB } from './identityDB';
|
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';
|
import { browser } from '$app/environment';
|
||||||
|
|
||||||
export type Account = BlahIdentityDescription & {
|
export type Account = BlahIdentityDescription & {
|
||||||
|
@ -106,6 +106,17 @@ class AccountManager {
|
||||||
await this.loadAccounts();
|
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(
|
async changePassword(
|
||||||
accountOrIdKeyId: Account | string,
|
accountOrIdKeyId: Account | string,
|
||||||
oldPassword: string,
|
oldPassword: string,
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
import PageHeader from '$lib/components/PageHeader.svelte';
|
import PageHeader from '$lib/components/PageHeader.svelte';
|
||||||
import { DocumentDuplicate, Key } from 'svelte-hero-icons';
|
import { DocumentDuplicate, Key } from 'svelte-hero-icons';
|
||||||
import ChangePasswordDialog from './ChangePasswordDialog.svelte';
|
import ChangePasswordDialog from './ChangePasswordDialog.svelte';
|
||||||
|
import ExportIdentityKeyDialog from './ExportIdentityKeyDialog.svelte';
|
||||||
|
|
||||||
let showChangePasswordDialog = $state(false);
|
let showChangePasswordDialog = $state(false);
|
||||||
|
let showExportIdentityDialog = $state(false);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<PageHeader>
|
<PageHeader>
|
||||||
|
@ -21,8 +23,16 @@
|
||||||
</GroupedListSection>
|
</GroupedListSection>
|
||||||
|
|
||||||
<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>
|
</GroupedListSection>
|
||||||
</GroupedListContainer>
|
</GroupedListContainer>
|
||||||
|
|
||||||
<ChangePasswordDialog bind:open={showChangePasswordDialog} />
|
<ChangePasswordDialog bind:open={showChangePasswordDialog} />
|
||||||
|
<ExportIdentityKeyDialog bind:open={showExportIdentityDialog} />
|
||||||
|
|
|
@ -190,6 +190,10 @@
|
||||||
<p>
|
<p>
|
||||||
Remember to change it on all other devices to which you granted <em>full access</em>.
|
Remember to change it on all other devices to which you granted <em>full access</em>.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
If you keeps backups of your identity, please update your backup file so it is encrypted
|
||||||
|
with the new password.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</GroupedListContainer>
|
</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