mirror of
https://github.com/librekeys/picoforge.git
synced 2026-07-28 08:01:19 -07:00
squash commits that implement #37 (pico-openpgp support). See branch pico-openpgp for detailed commits.
This commit is contained in:
committed by
Suyog Tandel
parent
bdba205be6
commit
ee528979e4
@@ -382,8 +382,12 @@ pub fn write_config(config: AppConfigInput, pin: Option<String>) -> Result<Strin
|
||||
log::info!("Starting FIDO write_config...");
|
||||
|
||||
let pin_val = pin.as_deref().ok_or_else(|| {
|
||||
log::error!("PIN is required for configuration");
|
||||
PFError::Device("PIN is required for configuration".into())
|
||||
log::error!(
|
||||
"A security PIN is required to be set to change the configuration in fido mode"
|
||||
);
|
||||
PFError::Device(
|
||||
"A security PIN is required to be set to change the configuration in fido mode".into(),
|
||||
)
|
||||
})?;
|
||||
|
||||
// 1. Obtain PIN token using the library handle
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<script lang="ts">
|
||||
import * as Alert from "$lib/components/ui/alert";
|
||||
import { TriangleAlert } from "@lucide/svelte";
|
||||
import { device } from "$lib/device/manager.svelte";
|
||||
|
||||
interface Props {
|
||||
message?: string;
|
||||
}
|
||||
|
||||
let { message = "This device does implement this feature." }: Props =
|
||||
$props();
|
||||
</script>
|
||||
|
||||
<Alert.Root variant={device.error ? "destructive" : "default"}>
|
||||
<TriangleAlert class="h-4 w-4" />
|
||||
<Alert.Title
|
||||
>{device.error ? "Connection Error" : "Feature not supported"}</Alert.Title
|
||||
>
|
||||
<Alert.Description>
|
||||
{device.error || message}
|
||||
</Alert.Description>
|
||||
</Alert.Root>
|
||||
@@ -0,0 +1,81 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import { Input } from "$lib/components/ui/input";
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
import * as Dialog from "$lib/components/ui/dialog";
|
||||
import * as Alert from "$lib/components/ui/alert";
|
||||
import { Loader2, Shield, Unlock } from "@lucide/svelte";
|
||||
import { device } from "$lib/device/manager.svelte";
|
||||
|
||||
let { open = $bindable(false), pin = $bindable("") } = $props();
|
||||
|
||||
let error = $state("");
|
||||
let loading = $state(false);
|
||||
|
||||
async function handleUnlock() {
|
||||
if (!pin) {
|
||||
error = "Please enter your PIN";
|
||||
return;
|
||||
}
|
||||
|
||||
loading = true;
|
||||
const res = await device.getCredentials(pin);
|
||||
|
||||
if (res.success) {
|
||||
open = false;
|
||||
// Reset state for next time
|
||||
// pin = ""; // Do not reset pin here, as it might be needed by the parent
|
||||
error = "";
|
||||
} else {
|
||||
error =
|
||||
typeof res.msg === "string" ? res.msg : "Failed to verify PIN";
|
||||
}
|
||||
|
||||
loading = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root bind:open>
|
||||
<Dialog.Content class="sm:max-w-md">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title class="flex items-center gap-2">
|
||||
<Shield class="h-5 w-5 text-primary" /> Authenticate to View Passkeys
|
||||
</Dialog.Title>
|
||||
<Dialog.Description
|
||||
>Enter your FIDO2 PIN to access and manage stored credentials.</Dialog.Description
|
||||
>
|
||||
</Dialog.Header>
|
||||
<div class="space-y-4 py-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="auth-pin">Device PIN</Label>
|
||||
<Input
|
||||
id="auth-pin"
|
||||
type="password"
|
||||
placeholder="Enter your PIN..."
|
||||
bind:value={pin}
|
||||
disabled={loading}
|
||||
onkeydown={(e) => e.key === "Enter" && handleUnlock()}
|
||||
autofocus
|
||||
/>
|
||||
</div>
|
||||
{#if error}
|
||||
<Alert.Root
|
||||
variant="destructive"
|
||||
class="animate-in fade-in slide-in-from-top-1"
|
||||
>
|
||||
<Alert.Description>{error}</Alert.Description>
|
||||
</Alert.Root>
|
||||
{/if}
|
||||
</div>
|
||||
<Dialog.Footer>
|
||||
<Button class="w-full" onclick={handleUnlock} disabled={loading}>
|
||||
{#if loading}
|
||||
<Loader2 class="mr-2 h-4 w-4 animate-spin" />
|
||||
Verifying...
|
||||
{:else}
|
||||
<Unlock class="mr-2 h-4 w-4" /> Unlock Storage
|
||||
{/if}
|
||||
</Button>
|
||||
</Dialog.Footer>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
@@ -0,0 +1,73 @@
|
||||
<script lang="ts">
|
||||
import * as AlertDialog from "$lib/components/ui/alert-dialog";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import { Input } from "$lib/components/ui/input";
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
import { Loader2 } from "@lucide/svelte";
|
||||
import type { StoredCredential } from "$lib/device/types.svelte";
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
credential: StoredCredential | null;
|
||||
loading: boolean;
|
||||
onDelete: () => void;
|
||||
}
|
||||
|
||||
let { open = $bindable(), credential, loading, onDelete }: Props = $props();
|
||||
|
||||
let deleteConfirmationInput = $state("");
|
||||
|
||||
$effect(() => {
|
||||
if (open) {
|
||||
deleteConfirmationInput = "";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<AlertDialog.Root bind:open>
|
||||
<AlertDialog.Content>
|
||||
<AlertDialog.Header>
|
||||
<AlertDialog.Title>Are you sure?</AlertDialog.Title>
|
||||
<AlertDialog.Description>
|
||||
This action cannot be undone. This will permanently delete the
|
||||
passkey for
|
||||
<span class="font-semibold text-foreground"
|
||||
>{credential?.rpId}</span
|
||||
>.
|
||||
</AlertDialog.Description>
|
||||
</AlertDialog.Header>
|
||||
|
||||
<div class="py-4 space-y-3">
|
||||
<Label for="confirm-delete">
|
||||
Type <span
|
||||
class="font-mono text-xs bg-muted px-1 py-0.5 rounded"
|
||||
>{credential?.rpId}</span
|
||||
> to confirm
|
||||
</Label>
|
||||
<Input
|
||||
id="confirm-delete"
|
||||
bind:value={deleteConfirmationInput}
|
||||
placeholder={credential?.rpId}
|
||||
autocomplete="off"
|
||||
class="font-mono"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<AlertDialog.Footer>
|
||||
<AlertDialog.Cancel disabled={loading}>Cancel</AlertDialog.Cancel>
|
||||
<Button
|
||||
variant="destructive"
|
||||
onclick={onDelete}
|
||||
disabled={deleteConfirmationInput !== credential?.rpId ||
|
||||
loading}
|
||||
>
|
||||
{#if loading}
|
||||
<Loader2 class="mr-2 h-4 w-4 animate-spin" />
|
||||
Deleting...
|
||||
{:else}
|
||||
Delete Passkey
|
||||
{/if}
|
||||
</Button>
|
||||
</AlertDialog.Footer>
|
||||
</AlertDialog.Content>
|
||||
</AlertDialog.Root>
|
||||
@@ -3,9 +3,9 @@ import type { DeviceConfig } from "$lib/device/types.svelte.ts";
|
||||
export const VENDORS = [
|
||||
{ value: "custom", label: "Custom (Manual Entry)", vid: "", pid: "" },
|
||||
{ value: "generic", label: "Generic (FEFF:FCFD)", vid: "FEFF", pid: "FCFD" },
|
||||
{ value: "pico-hsm", label: "Pico Keys HSM (2E8A:0x10FD)", vid: "2E8A", pid: "0x10FD" },
|
||||
{ value: "pico-fido", label: "Pico Keys Fido (2E8A:0x10FE)", vid: "2E8A", pid: "0x10FE" },
|
||||
{ value: "pico-openpgp", label: "Pico Keys OpenPGP (2E8A:0x10FF)", vid: "2E8A", pid: "0x10FF" },
|
||||
{ value: "pico-hsm", label: "Pico Keys HSM (2E8A:10FD)", vid: "2E8A", pid: "10FD" },
|
||||
{ value: "pico-fido", label: "Pico Keys Fido (2E8A:10FE)", vid: "2E8A", pid: "10FE" },
|
||||
{ value: "pico-openpgp", label: "Pico Keys OpenPGP (2E8A:10FF)", vid: "2E8A", pid: "10FF" },
|
||||
{ value: "pico", label: "Pico (2E8A:0003)", vid: "2E8A", pid: "0003" },
|
||||
{ value: "solokeys", label: "SoloKeys (0483:A2CA)", vid: "0483", pid: "A2CA" },
|
||||
{ value: "nitrohsm", label: "NitroHSM (20A0:4230)", vid: "20A0", pid: "4230" },
|
||||
|
||||
@@ -38,6 +38,10 @@ class DeviceManager {
|
||||
return match ? match.value : "custom";
|
||||
}
|
||||
|
||||
get hasFido() {
|
||||
return !!this.fidoInfo;
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
this.loading = true;
|
||||
this.error = null;
|
||||
@@ -63,9 +67,13 @@ class DeviceManager {
|
||||
|
||||
this.method = status.method;
|
||||
|
||||
const fido = await invoke<FidoInfo>("get_fido_info");
|
||||
|
||||
this.fidoInfo = fido;
|
||||
try {
|
||||
const fido = await invoke<FidoInfo>("get_fido_info");
|
||||
this.fidoInfo = fido;
|
||||
} catch (e) {
|
||||
logger.add("FIDO info could not be read (device might not support FIDO features)", "warning");
|
||||
this.fidoInfo = null;
|
||||
}
|
||||
|
||||
if (!this.connected) {
|
||||
logger.add(`Device Connected! Serial: ${this.info.serial}, FW: v${this.info.firmwareVersion}`, "success");
|
||||
|
||||
@@ -12,37 +12,53 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="space-y-6">
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold tracking-tight">About</h1>
|
||||
</div>
|
||||
|
||||
<Card.Root>
|
||||
<Card.Content class="pt-6">
|
||||
<div class="flex flex-col items-center justify-center space-y-4 text-center py-8">
|
||||
<div
|
||||
class="flex flex-col items-center justify-center space-y-4 text-center py-8"
|
||||
>
|
||||
<!-- <div class="bg-primary text-primary p-6 rounded-2xl"> -->
|
||||
<!-- <img src="/build-configure-symbolic.svg" alt="PicoForge Logo" class="h-12 w-12" /> -->
|
||||
<!-- </div> -->
|
||||
<img src="/in.suyogtandel.picoforge.svg" alt="PicoForge Logo" class="h-64 w-64 shadow-sm" />
|
||||
<img
|
||||
src="/in.suyogtandel.picoforge.svg"
|
||||
alt="PicoForge Logo"
|
||||
class="h-64 w-64 shadow-sm"
|
||||
/>
|
||||
|
||||
<h2 class="text-2xl font-bold">PicoForge</h2>
|
||||
<Badge variant="secondary" class="px-4 py-1">v0.3.0</Badge>
|
||||
<p class="text-muted-foreground max-w-md">
|
||||
An open source commissioning tool for Pico FIDO security keys. Developed with Rust, Tauri, and Svelte.
|
||||
An open source commissioning tool for Pico FIDO security keys.
|
||||
Developed with Rust, Tauri, and Svelte.
|
||||
</p>
|
||||
|
||||
<div class="text-sm text-muted-foreground space-y-1 pt-4 border-t w-full max-w-xs">
|
||||
<div
|
||||
class="text-sm text-muted-foreground space-y-1 pt-4 border-t w-full max-w-xs"
|
||||
>
|
||||
<div class="flex justify-between">
|
||||
<span>Code By:</span> <span class="font-medium text-foreground">Suyog Tandel</span>
|
||||
<span>Code By:</span>
|
||||
<span class="font-medium text-foreground">Suyog Tandel</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center pt-2 mt-2">
|
||||
<span class="flex items-center gap-1">Copyright:</span>
|
||||
<span class="font-medium text-foreground">© 2026 Suyog Tandel</span>
|
||||
<span class="font-medium text-foreground">© 2026 Suyog Tandel</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-4 pt-6">
|
||||
<Button variant="outline" size="sm" class="gap-2" onclick={openGithub}>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="gap-2"
|
||||
onclick={openGithub}
|
||||
>
|
||||
<Github class="h-4 w-4" />
|
||||
GitHub
|
||||
</Button>
|
||||
|
||||
@@ -12,55 +12,32 @@
|
||||
import { device } from "$lib/device/manager.svelte";
|
||||
import { LED_DRIVERS, VENDORS } from "$lib/device/constants.svelte";
|
||||
|
||||
import { Microchip, RefreshCw, Save, Settings, Tag, TriangleAlert, X, Key } from "@lucide/svelte";
|
||||
import {
|
||||
Microchip,
|
||||
RefreshCw,
|
||||
Save,
|
||||
Settings,
|
||||
Tag,
|
||||
TriangleAlert,
|
||||
X,
|
||||
} from "@lucide/svelte";
|
||||
|
||||
import { configViewState as state } from "$lib/state/configState.svelte";
|
||||
import NoDeviceStatus from "$lib/components/device/NoDeviceStatus.svelte";
|
||||
</script>
|
||||
|
||||
<div class="space-y-6">
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold tracking-tight">Configuration</h1>
|
||||
<p class="text-muted-foreground">Customize device settings and behavior.</p>
|
||||
</div>
|
||||
|
||||
{#if !device.connected}
|
||||
<NoDeviceStatus message="Connect your device to access configuration options." />
|
||||
<NoDeviceStatus
|
||||
message="Connect your device to access configuration options."
|
||||
/>
|
||||
{:else}
|
||||
<div class="grid gap-6 lg:grid-cols-2">
|
||||
<Card.Root class="lg:col-span-2">
|
||||
<Card.Header>
|
||||
<Card.Title class="flex items-center gap-2">
|
||||
<Key class="h-5 w-5" />
|
||||
PIN Management
|
||||
</Card.Title>
|
||||
<Card.Description>Configure FIDO2 PIN security</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Content class="space-y-4">
|
||||
<div class="flex items-center justify-between p-4 border rounded-lg">
|
||||
<div class="space-y-1">
|
||||
<p class="font-medium">Current PIN Status</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{device.fidoInfo?.options?.clientPin ? "PIN is set" : "No PIN configured"}
|
||||
</p>
|
||||
</div>
|
||||
<Button variant="outline" onclick={() => state.openPinDialog()}>
|
||||
{device.fidoInfo?.options?.clientPin ? "Change PIN" : "Set PIN"}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between p-4 border rounded-lg">
|
||||
<div class="space-y-1">
|
||||
<p class="font-medium">Minimum PIN Length</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Current: {device.fidoInfo?.minPinLength || 4} characters
|
||||
</p>
|
||||
</div>
|
||||
<Button variant="outline" disabled={!device.fidoInfo?.options?.clientPin} onclick={() => state.openMinPinDialog()}>Update Minimum Length</Button>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title class="flex items-center gap-2">
|
||||
@@ -79,7 +56,8 @@
|
||||
disabled={!device.connected}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
{VENDORS.find((v) => v.value === device.selectedVendor)?.label ?? "Select a vendor"}
|
||||
{VENDORS.find((v) => v.value === device.selectedVendor)
|
||||
?.label ?? "Select a vendor"}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each VENDORS as vendor}
|
||||
@@ -99,7 +77,8 @@
|
||||
bind:value={device.config.vid}
|
||||
maxlength={4}
|
||||
placeholder="CAFE"
|
||||
disabled={!device.connected || device.selectedVendor !== "custom"}
|
||||
disabled={!device.connected ||
|
||||
device.selectedVendor !== "custom"}
|
||||
class="font-mono"
|
||||
/>
|
||||
</div>
|
||||
@@ -110,7 +89,8 @@
|
||||
bind:value={device.config.pid}
|
||||
maxlength={4}
|
||||
placeholder="4242"
|
||||
disabled={!device.connected || device.selectedVendor !== "custom"}
|
||||
disabled={!device.connected ||
|
||||
device.selectedVendor !== "custom"}
|
||||
class="font-mono"
|
||||
/>
|
||||
</div>
|
||||
@@ -120,7 +100,12 @@
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="product">Product Name</Label>
|
||||
<Input id="product" bind:value={device.config.productName} placeholder="My Key" disabled={!device.connected} />
|
||||
<Input
|
||||
id="product"
|
||||
bind:value={device.config.productName}
|
||||
placeholder="My Key"
|
||||
disabled={!device.connected}
|
||||
/>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
@@ -136,14 +121,25 @@
|
||||
<Card.Content class="space-y-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="led-gpio">LED GPIO Pin</Label>
|
||||
<Input id="led-gpio" type="number" bind:value={device.config.ledGpio} min="0" max="29" />
|
||||
<Input
|
||||
id="led-gpio"
|
||||
type="number"
|
||||
bind:value={device.config.ledGpio}
|
||||
min="0"
|
||||
max="29"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="led-driver">LED Driver</Label>
|
||||
<Select.Root type="single" bind:value={device.config.ledDriver} disabled={!device.connected}>
|
||||
<Select.Root
|
||||
type="single"
|
||||
bind:value={device.config.ledDriver}
|
||||
disabled={!device.connected}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
{LED_DRIVERS.find((d) => d.value === device.config.ledDriver)?.label ?? "Select driver"}
|
||||
{LED_DRIVERS.find((d) => d.value === device.config.ledDriver)
|
||||
?.label ?? "Select driver"}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each LED_DRIVERS as driver}
|
||||
@@ -168,14 +164,18 @@
|
||||
disabled={!device.connected}
|
||||
class="flex-1"
|
||||
/>
|
||||
<span class="text-xs text-muted-foreground min-w-[4ch]">Level {device.config.ledBrightness}</span>
|
||||
<span class="text-xs text-muted-foreground min-w-[4ch]"
|
||||
>Level {device.config.ledBrightness}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between space-x-2">
|
||||
<div class="space-y-0.5">
|
||||
<Label>LED Dimmable</Label>
|
||||
<p class="text-sm text-muted-foreground">Allow brightness adjustment</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Allow brightness adjustment
|
||||
</p>
|
||||
</div>
|
||||
<Switch bind:checked={device.config.ledDimmable} />
|
||||
</div>
|
||||
@@ -183,7 +183,9 @@
|
||||
<div class="flex items-center justify-between space-x-2">
|
||||
<div class="space-y-0.5">
|
||||
<Label>LED Steady Mode</Label>
|
||||
<p class="text-sm text-muted-foreground">Keep LED on constantly</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Keep LED on constantly
|
||||
</p>
|
||||
</div>
|
||||
<Switch bind:checked={device.config.ledSteady} />
|
||||
</div>
|
||||
@@ -201,7 +203,13 @@
|
||||
<Card.Content class="space-y-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="touch-timeout">Touch Timeout (seconds)</Label>
|
||||
<Input id="touch-timeout" type="number" bind:value={device.config.touchTimeout} min="1" max="255" />
|
||||
<Input
|
||||
id="touch-timeout"
|
||||
type="number"
|
||||
bind:value={device.config.touchTimeout}
|
||||
min="1"
|
||||
max="255"
|
||||
/>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
@@ -218,7 +226,9 @@
|
||||
<div class="flex items-center justify-between space-x-2">
|
||||
<div class="space-y-0.5">
|
||||
<Label>Power Cycle on Reset</Label>
|
||||
<p class="text-sm text-muted-foreground">Restart device on reset</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Restart device on reset
|
||||
</p>
|
||||
</div>
|
||||
<Switch bind:checked={device.config.powerCycleOnReset} />
|
||||
</div>
|
||||
@@ -226,7 +236,9 @@
|
||||
<div class="flex items-center justify-between space-x-2">
|
||||
<div class="space-y-0.5">
|
||||
<Label>Enable Secp256k1</Label>
|
||||
<p class="text-sm text-muted-foreground">Does not work on Android!</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Does not work on Android!
|
||||
</p>
|
||||
</div>
|
||||
<Switch bind:checked={device.config.enableSecp256k1} />
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
import NoDeviceStatus from "$lib/components/device/NoDeviceStatus.svelte";
|
||||
</script>
|
||||
|
||||
<div class="space-y-6">
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold tracking-tight">Device Overview</h1>
|
||||
<p class="text-muted-foreground">
|
||||
|
||||
@@ -8,24 +8,35 @@
|
||||
import { Terminal } from "@lucide/svelte";
|
||||
</script>
|
||||
|
||||
<div class="space-y-6 h-full flex flex-col">
|
||||
<div class="space-y-4 h-full flex flex-col">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold tracking-tight">System Logs</h1>
|
||||
<p class="text-muted-foreground">Real-time device communication and application events.</p>
|
||||
<p class="text-muted-foreground">
|
||||
Real-time device communication and application events.
|
||||
</p>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" onclick={() => (logger.logs = [])}>Clear Logs</Button>
|
||||
<Button variant="outline" size="sm" onclick={() => (logger.logs = [])}
|
||||
>Clear Logs</Button
|
||||
>
|
||||
</div>
|
||||
|
||||
<Card.Root class="flex-1 flex flex-col min-h-[500px] bg-black border-zinc-800">
|
||||
<Card.Root
|
||||
class="flex-1 flex flex-col min-h-[500px] bg-black border-zinc-800"
|
||||
>
|
||||
<Card.Content class="p-0 flex-1 flex flex-col">
|
||||
{#if logger.logs.length === 0}
|
||||
<div class="flex-1 flex flex-col items-center justify-center text-zinc-500">
|
||||
<div
|
||||
class="flex-1 flex flex-col items-center justify-center text-zinc-500"
|
||||
>
|
||||
<Terminal class="h-12 w-12 mb-4 opacity-50" />
|
||||
<p>No events recorded yet.</p>
|
||||
</div>
|
||||
{:else}
|
||||
<ScrollArea class="h-[500px] p-4 font-mono text-sm" orientation="vertical">
|
||||
<ScrollArea
|
||||
class="h-[500px] p-4 font-mono text-sm"
|
||||
orientation="vertical"
|
||||
>
|
||||
<div class="space-y-1">
|
||||
{#each logger.logs as log}
|
||||
<div class="flex gap-3">
|
||||
|
||||
+284
-243
File diff suppressed because it is too large
Load Diff
@@ -12,32 +12,43 @@
|
||||
import { Lock, TriangleAlert } from "@lucide/svelte";
|
||||
|
||||
async function lockDevice() {
|
||||
logger.add("Action Blocked: Secure Boot toggle attempted but feature is disabled.", "warning");
|
||||
logger.add(
|
||||
"Action Blocked: Secure Boot toggle attempted but feature is disabled.",
|
||||
"warning",
|
||||
);
|
||||
return;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="space-y-6">
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold tracking-tight text-destructive">Secure Boot</h1>
|
||||
<p class="text-muted-foreground">Permanently lock this device to the current firmware vendor.</p>
|
||||
<h1 class="text-3xl font-bold tracking-tight text-destructive">
|
||||
Secure Boot
|
||||
</h1>
|
||||
<p class="text-muted-foreground">
|
||||
Permanently lock this device to the current firmware vendor.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Alert.Root variant="destructive">
|
||||
<TriangleAlert class="h-4 w-4" />
|
||||
<Alert.Title>Feature Unstable</Alert.Title>
|
||||
<Alert.Description>This feature is currently under work and disabled for safety.</Alert.Description>
|
||||
<Alert.Description
|
||||
>This feature is currently under work and disabled for safety.</Alert.Description
|
||||
>
|
||||
</Alert.Root>
|
||||
|
||||
<Card.Root class="border-destructive/30 opacity-60">
|
||||
<Card.Header>
|
||||
<Card.Title>Lock Settings</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Content class="space-y-6 pointer-events-none">
|
||||
<Card.Content class="space-y-4 pointer-events-none">
|
||||
<div class="flex items-center justify-between space-x-2">
|
||||
<div class="flex flex-col space-y-1">
|
||||
<Label for="secure-boot">Enable Secure Boot</Label>
|
||||
<p class="font-normal text-xs text-muted-foreground">Verifies firmware signature on startup</p>
|
||||
<p class="font-normal text-xs text-muted-foreground">
|
||||
Verifies firmware signature on startup
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
id="secure-boot"
|
||||
@@ -50,16 +61,30 @@
|
||||
<div class="flex items-center justify-between space-x-2">
|
||||
<div class="flex flex-col space-y-1">
|
||||
<Label for="secure-lock">Secure Lock</Label>
|
||||
<p class="font-normal text-xs text-muted-foreground">Prevents reading key material via debug ports</p>
|
||||
<p class="font-normal text-xs text-muted-foreground">
|
||||
Prevents reading key material via debug ports
|
||||
</p>
|
||||
</div>
|
||||
<Switch id="secure-lock" bind:checked={device.security.secureLock} disabled={true} />
|
||||
<Switch
|
||||
id="secure-lock"
|
||||
bind:checked={device.security.secureLock}
|
||||
disabled={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div class="flex items-center space-x-2 bg-destructive/10 p-4 rounded-md border border-destructive/20">
|
||||
<Switch id="confirm" bind:checked={device.security.confirmed} disabled={true} />
|
||||
<Label for="confirm" class="text-destructive font-medium">I understand the risks of bricking my device.</Label>
|
||||
<div
|
||||
class="flex items-center space-x-2 bg-destructive/10 p-4 rounded-md border border-destructive/20"
|
||||
>
|
||||
<Switch
|
||||
id="confirm"
|
||||
bind:checked={device.security.confirmed}
|
||||
disabled={true}
|
||||
/>
|
||||
<Label for="confirm" class="text-destructive font-medium"
|
||||
>I understand the risks of bricking my device.</Label
|
||||
>
|
||||
</div>
|
||||
</Card.Content>
|
||||
<Card.Footer class="border-t bg-muted/20 px-6 py-4 flex justify-end">
|
||||
|
||||
Reference in New Issue
Block a user