add settings page with reset app: clears keychain secrets and SQLite cache
This commit is contained in:
@@ -28,6 +28,13 @@ import {
|
||||
MoneroWalletManager,
|
||||
} from './lib/monero'
|
||||
import { canPromptTouchID, promptTouchID } from './lib/biometric'
|
||||
import { sqlite } from './lib/sqlite'
|
||||
import {
|
||||
tokenMetadata,
|
||||
transactions,
|
||||
transactionReceipts,
|
||||
txHistory,
|
||||
} from './lib/db/schema'
|
||||
|
||||
const env = getENV()
|
||||
|
||||
@@ -134,6 +141,10 @@ type TxEntry = {
|
||||
type RPC = {
|
||||
bun: RPCSchema<{
|
||||
requests: {
|
||||
resetApp: {
|
||||
params: {}
|
||||
response: boolean
|
||||
}
|
||||
biometricCanAuth: {
|
||||
params: {}
|
||||
response: boolean
|
||||
@@ -366,6 +377,24 @@ const rpc = BrowserView.defineRPC<RPC>({
|
||||
maxRequestTime: 120000,
|
||||
handlers: {
|
||||
requests: {
|
||||
resetApp: async () => {
|
||||
try {
|
||||
await Promise.all([
|
||||
Bun.secrets.delete({ service: 'koins', name: 'vault' }),
|
||||
Bun.secrets.delete({ service: 'koins', name: 'vault_password' }),
|
||||
Bun.secrets.delete({ service: 'koins', name: 'alchemy_key' }),
|
||||
])
|
||||
sqlite.run('DELETE FROM token_metadata')
|
||||
sqlite.run('DELETE FROM transactions')
|
||||
sqlite.run('DELETE FROM transaction_receipts')
|
||||
sqlite.run('DELETE FROM tx_history')
|
||||
console.log('[rpc] resetApp complete')
|
||||
return true
|
||||
} catch (e) {
|
||||
console.log('[rpc] resetApp error:', e)
|
||||
return false
|
||||
}
|
||||
},
|
||||
biometricCanAuth: async () => {
|
||||
try {
|
||||
return canPromptTouchID()
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import ArrowDown from '@lucide/svelte/icons/arrow-down'
|
||||
import ArrowUp from '@lucide/svelte/icons/arrow-up'
|
||||
import QrCodeIcon from '@lucide/svelte/icons/qr-code'
|
||||
import SettingsIcon from '@lucide/svelte/icons/settings'
|
||||
import Fingerprint from '@lucide/svelte/icons/fingerprint'
|
||||
import * as Dialog from '$lib/components/ui/dialog/index.js'
|
||||
import QRCode from 'qrcode'
|
||||
@@ -252,6 +253,9 @@
|
||||
<Button onclick={() => w.refresh()} disabled={w.loading}>
|
||||
{w.loading ? 'Refreshing...' : 'Refresh'}
|
||||
</Button>
|
||||
<Button variant="outline" onclick={() => navigate('/settings')}>
|
||||
<SettingsIcon size={16} />
|
||||
</Button>
|
||||
<Button variant="outline" onclick={() => w.lock()}>
|
||||
Lock
|
||||
</Button>
|
||||
|
||||
@@ -92,6 +92,10 @@ export type TokenBalanceResult = {
|
||||
type RPC = {
|
||||
bun: {
|
||||
requests: {
|
||||
resetApp: {
|
||||
params: {}
|
||||
response: boolean
|
||||
}
|
||||
biometricCanAuth: {
|
||||
params: {}
|
||||
response: boolean
|
||||
|
||||
@@ -199,6 +199,24 @@ export const Wallet = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const resetApp = async () => {
|
||||
if (!electrobun.rpc) return false
|
||||
const [ok] = await tryCatch(
|
||||
electrobun.rpc.request.resetApp({}),
|
||||
)
|
||||
if (!ok) return false
|
||||
seed = ''
|
||||
address = ''
|
||||
balance = '0'
|
||||
error = ''
|
||||
tokenBalances = []
|
||||
transactions = []
|
||||
apiKey = ''
|
||||
vaultExists = false
|
||||
passwordHash = ''
|
||||
return true
|
||||
}
|
||||
|
||||
const setPassword = async (password: string) => {
|
||||
if (!electrobun.rpc) return
|
||||
const ph = await hashPassword(password)
|
||||
@@ -473,6 +491,7 @@ export const Wallet = () => {
|
||||
unlockWithBiometrics,
|
||||
unlockWithPassword,
|
||||
setPassword,
|
||||
resetApp,
|
||||
saveVault,
|
||||
switchNetwork,
|
||||
saveApiKey,
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<script lang="ts">
|
||||
import { wallet } from '$lib/states/wallet.svelte.js'
|
||||
import { Button } from '$lib/components/ui/button/index.js'
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from '$lib/components/ui/card/index.js'
|
||||
import { navigate } from 'sv-router/generated'
|
||||
|
||||
const w = wallet
|
||||
let confirm = $state(false)
|
||||
let resetting = $state(false)
|
||||
|
||||
async function handleReset() {
|
||||
resetting = true
|
||||
const ok = await w.resetApp()
|
||||
if (ok) navigate('/')
|
||||
resetting = false
|
||||
confirm = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="mx-auto mt-16 max-w-md">
|
||||
<div class="flex flex-col gap-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Settings</CardTitle>
|
||||
<CardDescription>App preferences and data management</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent class="space-y-4">
|
||||
<div>
|
||||
<p class="font-medium text-xs">Reset App</p>
|
||||
<p class="text-muted-foreground text-xs mt-1">
|
||||
Removes your seed, API key, and all cached data from the keychain
|
||||
and database. You can then set up the wallet fresh.
|
||||
</p>
|
||||
<div class="mt-3">
|
||||
{#if confirm}
|
||||
<div class="flex gap-2 items-center">
|
||||
<p class="text-xs text-red-500">Are you sure?</p>
|
||||
<Button size="sm" variant="destructive" onclick={handleReset} disabled={resetting}>
|
||||
{resetting ? 'Resetting...' : 'Yes, reset everything'}
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" onclick={() => (confirm = false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
{:else}
|
||||
<Button variant="outline" onclick={() => (confirm = true)}>
|
||||
Reset App
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user