add Touch ID wallet unlock via Swift biometric helper + Bun spawn
This commit is contained in:
@@ -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 Fingerprint from '@lucide/svelte/icons/fingerprint'
|
||||
import * as Dialog from '$lib/components/ui/dialog/index.js'
|
||||
import QRCode from 'qrcode'
|
||||
|
||||
@@ -101,8 +102,26 @@
|
||||
</Card>
|
||||
{:else if w.isLocked}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Wallet Locked</CardTitle>
|
||||
<CardDescription>Your seed is stored in the system keychain</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p class="text-muted-foreground text-xs">Unlocking...</p>
|
||||
{#if w.biometricAvailable}
|
||||
<Button
|
||||
onclick={() => w.unlockWithBiometrics()}
|
||||
disabled={w.loading}>
|
||||
<Fingerprint size={16} />
|
||||
{w.loading ? 'Unlocking...' : 'Unlock with Touch ID'}
|
||||
</Button>
|
||||
{:else}
|
||||
<p class="text-muted-foreground text-xs">
|
||||
Touch ID not available on this device
|
||||
</p>
|
||||
{/if}
|
||||
{#if w.error}
|
||||
<p class="mt-3 text-red-500">{w.error}</p>
|
||||
{/if}
|
||||
</CardContent>
|
||||
</Card>
|
||||
{:else}
|
||||
|
||||
@@ -92,6 +92,14 @@ export type TokenBalanceResult = {
|
||||
type RPC = {
|
||||
bun: {
|
||||
requests: {
|
||||
biometricCanAuth: {
|
||||
params: {}
|
||||
response: boolean
|
||||
}
|
||||
biometricAuth: {
|
||||
params: { reason: string }
|
||||
response: boolean
|
||||
}
|
||||
getSecret: {
|
||||
params: {
|
||||
service: string
|
||||
|
||||
@@ -77,6 +77,7 @@ export const Wallet = () => {
|
||||
let moneroTxs = $state<MoneroTxEntry[]>([])
|
||||
let moneroInstalled = $state(false)
|
||||
let moneroDownloading = $state(false)
|
||||
let biometricAvailable = $state(false)
|
||||
let moneroWalletName = $state('')
|
||||
let moneroAccounts = $state<MoneroAccountEntry[]>([])
|
||||
let moneroWallets = $state<string[]>([])
|
||||
@@ -115,6 +116,7 @@ export const Wallet = () => {
|
||||
seed = raw
|
||||
await refresh()
|
||||
}
|
||||
await checkBiometric()
|
||||
try {
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
@@ -159,6 +161,32 @@ export const Wallet = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const checkBiometric = async () => {
|
||||
if (!electrobun.rpc) return
|
||||
const [ok] = await tryCatch(
|
||||
electrobun.rpc.request.biometricCanAuth({}),
|
||||
)
|
||||
biometricAvailable = ok === true
|
||||
}
|
||||
|
||||
const unlockWithBiometrics = async () => {
|
||||
if (!electrobun.rpc) return false
|
||||
const [authed] = await tryCatch(
|
||||
electrobun.rpc.request.biometricAuth({ reason: 'Unlock wallet' }),
|
||||
)
|
||||
if (!authed) return false
|
||||
const [raw] = await tryCatch(
|
||||
electrobun.rpc.request.getSecret({
|
||||
service: 'koins',
|
||||
name: 'vault',
|
||||
}),
|
||||
)
|
||||
if (!raw) return false
|
||||
seed = raw
|
||||
await refresh()
|
||||
return true
|
||||
}
|
||||
|
||||
const lock = () => {
|
||||
seed = ''
|
||||
address = ''
|
||||
@@ -399,9 +427,11 @@ export const Wallet = () => {
|
||||
get moneroWalletName() { return moneroWalletName },
|
||||
get moneroAccounts() { return moneroAccounts },
|
||||
get moneroWallets() { return moneroWallets },
|
||||
get biometricAvailable() { return biometricAvailable },
|
||||
refresh,
|
||||
init,
|
||||
lock,
|
||||
unlockWithBiometrics,
|
||||
saveVault,
|
||||
switchNetwork,
|
||||
saveApiKey,
|
||||
|
||||
Reference in New Issue
Block a user