diff --git a/deno.json b/deno.json index 42d73e9..1751057 100644 --- a/deno.json +++ b/deno.json @@ -4,7 +4,7 @@ "fmt": { "useTabs": false, "indentWidth": 2, - "lineWidth": 120, + "lineWidth": 140, "include": ["src"], diff --git a/src-tauri/src/fido.rs b/src-tauri/src/fido.rs index b6d5771..e7fb145 100644 --- a/src-tauri/src/fido.rs +++ b/src-tauri/src/fido.rs @@ -1,6 +1,33 @@ use ctap_hid_fido2::{Cfg, FidoKeyHidFactory}; +use crate::types::FidoDeviceInfo; +use std::collections::HashMap; // use ctap_hid_fido2::fidokey::FidoKeyHid; +#[tauri::command] +pub(crate) fn get_fido_info() -> Result { + let cfg = Cfg::init(); + + let device = FidoKeyHidFactory::create(&cfg) + .map_err(|_| "Could not connect to FIDO device. Is it plugged in?".to_string())?; + + let info = device + .get_info() + .map_err(|e| format!("Error reading device info: {:?}", e))?; + + let options_map: HashMap = info.options.into_iter().collect(); + + Ok(FidoDeviceInfo { + versions: info.versions, + extensions: info.extensions, + aaguid: hex::encode_upper(info.aaguid), + options: options_map, + max_msg_size: info.max_msg_size, + pin_protocols: info.pin_uv_auth_protocols, + min_pin_length: info.min_pin_length, + firmware_version: format!("0x{:X}", info.firmware_version), + }) +} + #[tauri::command] pub(crate) fn change_fido_pin( current_pin: Option, diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 3d1e0d2..26ccb4b 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -17,6 +17,7 @@ pub fn run() { rescue::read_device_details, rescue::get_device_info, rescue::write_config, + fido::get_fido_info, fido::change_fido_pin, fido::set_min_pin_length, rescue::enable_secure_boot diff --git a/src-tauri/src/types.rs b/src-tauri/src/types.rs index 2757352..0dabcfd 100644 --- a/src-tauri/src/types.rs +++ b/src-tauri/src/types.rs @@ -78,6 +78,24 @@ pub struct FullDeviceStatus { pub secure_lock: bool, } +// Fido stuff: + +#[derive(Serialize)] +pub struct FidoDeviceInfo { + pub versions: Vec, + pub extensions: Vec, + pub aaguid: String, + pub options: std::collections::HashMap, + pub max_msg_size: i32, + pub pin_protocols: Vec, + // pub remaining_disc_creds: u32, + pub min_pin_length: u32, + pub firmware_version: String, +} + + +// Error stuff: + #[derive(Debug, thiserror::Error)] pub enum AppError { #[error("PCSC Error: {0}")] diff --git a/src/lib/device/manager.svelte.ts b/src/lib/device/manager.svelte.ts index 1d329fd..19b040c 100644 --- a/src/lib/device/manager.svelte.ts +++ b/src/lib/device/manager.svelte.ts @@ -1,11 +1,12 @@ import { invoke } from "@tauri-apps/api/core"; import { logger } from "$lib/utils/log.svelte"; import { DEFAULT_CONFIG, DEFAULT_DEVICE_INFO, VENDORS } from "$lib/device/constants.svelte"; -import type { DeviceConfig, DeviceInfo, SecurityState } from "$lib/device/types.svelte"; +import type { DeviceConfig, DeviceInfo, FidoInfo, SecurityState } from "$lib/device/types.svelte"; class DeviceManager { loading = $state(false); connected = $state(false); + fidoInfo: FidoInfo | null = $state(null); config: DeviceConfig = $state({ ...DEFAULT_CONFIG }); info: DeviceInfo = $state({ ...DEFAULT_DEVICE_INFO }); @@ -60,6 +61,19 @@ class DeviceManager { confirmed: false, }; + const fido: any = await invoke("get_fido_info"); + this.fidoInfo = { + versions: fido.versions, + extensions: fido.extensions, + aaguid: fido.aaguid, + options: fido.options, + maxMsgSize: fido.max_msg_size, + pinProtocols: fido.pin_protocols, + // remainingDiscCreds: fido.remaining_disc_creds, + minPinLength: fido.min_pin_length, + firmwareVersion: fido.firmware_version, + }; + if (!this.connected) { logger.add( `Device Connected! Serial: ${this.info.serial}, FW: v${this.info.firmwareVersion}`, @@ -162,6 +176,29 @@ class DeviceManager { logger.add(`Selected vendor preset: ${v.label}`, "info"); } } + + async changePin(current: string | null, next: string) { + try { + const res = await invoke("change_fido_pin", { currentPin: current, newPin: next }); + logger.add(res as string, "success"); + return { success: true }; + } catch (err) { + logger.add(`PIN Error: ${err}`, "error"); + return { success: false, msg: err }; + } + } + + async updateMinPinLength(currentPin: string, length: number) { + try { + const res = await invoke("set_min_pin_length", { currentPin, minPinLength: length }); + logger.add(res as string, "success"); + await this.refresh(); + return { success: true }; + } catch (err) { + logger.add(`Min PIN Error: ${err}`, "error"); + return { success: false, msg: err }; + } + } } export const device = new DeviceManager(); diff --git a/src/lib/device/types.svelte.ts b/src/lib/device/types.svelte.ts index 8c65c96..a3eb425 100644 --- a/src/lib/device/types.svelte.ts +++ b/src/lib/device/types.svelte.ts @@ -24,3 +24,15 @@ export interface SecurityState { secureLock: boolean; confirmed: boolean; } + +export interface FidoInfo { + versions: string[]; + extensions: string[]; + aaguid: string; + options: Record; + maxMsgSize: number; + pinProtocols: number[]; + // remainingDiscCreds: number; + minPinLength: number; + firmwareVersion: string; +} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 753d1b0..c5e3e52 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,798 +1,1090 @@
-
-
+
+
-
- +
+ - + - -
-
+ +
+ -
- -
- -
-
- {#if currentView === "home"} -
-
-
-

Device Status

-

Overview of connected hardware.

-
- -
+
+ +
+
+ {#if currentView === "home"} +
+
+

Device Overview

+

+ Quick view of your device status and specifications. +

+
-
- - - Product Name - - - -
- {device.connected ? device.config.productName : "---"} -
-

- VID: {device.connected ? device.config.vid : "--"} | PID: { - device.connected ? device.config.pid : "--" - } -

-
-
+ {#if !device.connected} + + + No Device Connected + + Please connect your device and click Refresh to begin. + + + {:else} +
+ + + + + Device Information + + + +
+
+

Serial Number

+

{device.info.serial}

+
+
+

Firmware Version

+

v{device.info.firmwareVersion}

+
+
+

VID:PID

+

{device.config.vid}:{device.config.pid}

+
+
+

Product Name

+

{device.config.productName}

+
+
- - - Serial Number - - - -
- {device.connected ? device.info.serial : "---"} -
-
-
+ - - - Flash Usage - - - -
- { - device.connected - ? `${device.info.flashUsed} / ${device.info.flashTotal} KB` - : "---" - } -
- 0 - ? (device.info.flashUsed / - device.info.flashTotal) * - 100 - : 0} - max={100} - class="mt-3" - /> -
-
+
+
+ Flash Memory + + {device.info.flashUsed} / {device.info.flashTotal} KB + +
+ +
+
+
- - - Firmware - - - -
- {device.connected ? `v${device.info.firmwareVersion}` : "---"} -
-
-
+ + + + + FIDO2 Information + + + + {#if device.fidoInfo} +
+
+

FIDO Version

+

{device.fidoInfo.versions[0] || "N/A"}

+
+
+

PIN Set

+

+ {device.fidoInfo.options?.clientPin ? "Yes" : "No"} +

+
+
+

Min PIN Length

+

{device.fidoInfo.minPinLength}

+
+
+

Resident Keys

+

+ {device.fidoInfo.options?.rk ? "Supported" : "Not Supported"} +

+
+
- - - Security Status - {#if device.security.secureBoot} - - {:else} - - {/if} - - -
- { - device.connected - ? (device.security.secureBoot ? "Secure Boot" : "Development") - : "---" - } -
-

- { - device.connected - ? (device.security.secureLock ? "Read-out Locked" : "Debug Enabled") - : "" - } -

-
-
-
+ - {#if !device.connected} - - - No Device Detected - - Please plug in your Pico FIDO key. If you are on Linux, ensure you have the correct udev rules - installed. - - - {/if} -
- {/if} +
+

AAGUID

+

{device.fidoInfo.aaguid}

+
+ {:else} +

FIDO information not available

+ {/if} + + - {#if currentView === "config"} -
-
-

Configuration

-

- Customize your key's identity and hardware behavior. -

-
+ + + + + LED Configuration + + + +
+ LED GPIO Pin + GPIO {device.config.ledGpio} +
+
+ LED Brightness + {device.config.ledBrightness} +
+
+ Presence Touch Timeout + {device.config.touchTimeout}s +
+
+ LED Dimmable + + {device.config.ledDimmable ? "Yes" : "No"} + +
+
+ LED Steady Mode + + {device.config.ledSteady ? "On" : "Off"} + +
+
+
- - - Identity - USB Identification settings - - -
- - - - { - VENDORS.find( - (v) => - v.value === - device.selectedVendor, - )?.label ?? - "Select a vendor" - } - - - {#each VENDORS as vendor} - - { - vendor - .label - } - - {/each} - - -
+ + + + + Vendor Information + + + +
+ Vendor ID + {device.config.vid} +
+
+ Product ID + {device.config.pid} +
+
+ Selected Vendor + + {VENDORS.find((v) => v.value === device.selectedVendor)?.label || "Custom"} + +
+
+
+
+ {/if} +
+ {/if} -
-
- - -
-
- - -
-
-
- - -
- - + {#if currentView === "config"} +
+
+

Configuration

+

+ Customize device settings and behavior. +

+
- - - Curves - Cryptographic Curve Settings - - -
- - -
-
-
+ {#if !device.connected} + + + No Device Connected + + Connect your device to access configuration options. + + + {:else} +
+ + + + + PIN Management + + Configure FIDO2 PIN security + + +
+
+

Current PIN Status

+

+ {device.fidoInfo?.options?.clientPin ? "PIN is set" : "No PIN configured"} +

+
+ +
- - - Hardware & Behavior - LED settings and timeouts - - -
-
- - -
-
- - -
-
+
+
+

Minimum PIN Length

+

+ Current: {device.fidoInfo?.minPinLength || 4} characters +

+
+ +
+
+
-
- - - - { - LED_DRIVERS.find( - (d) => - d.value === - device.config - .ledDriver, - )?.label ?? - "Select Driver" - } - - - {#each LED_DRIVERS as driver} - - { - driver - .label - } - - {/each} - - -
+ + + + + Identity + + USB Identification settings + + +
+ + + + {VENDORS.find((v) => v.value === device.selectedVendor)?.label ?? "Select a vendor"} + + + {#each VENDORS as vendor} + + {vendor.label} + + {/each} + + +
+
+
+ + +
+
+ + +
+
- + -
- - -
+
+ + +
+
+
-
- - -
+ + + + + LED Settings + + Adjust visual feedback behavior + + +
+ + +
-
- - -
-
-
- - Level { - device.config - .ledBrightness - } -
- -
-
- - - -
-
- {/if} +
+ + + + {LED_DRIVERS.find((d) => d.value === device.config.ledDriver)?.label ?? "Select driver"} + + + {#each LED_DRIVERS as driver} + + {driver.label} + + {/each} + + +
- {#if currentView === "security"} -
-
-

Secure Boot

-

- Permanently lock this device to the current firmware vendor. -

-
+ - - - Feature Unstable - - This feature is currently under work and disabled for safety. - - +
+ +
+ + Level {device.config.ledBrightness} +
+
- - - Lock Settings - - -
-
- -

- Verifies firmware signature on startup -

-
- -
+
+
+ +

Allow brightness adjustment

+
+ +
-
-
- -

- Prevents reading key material via debug ports -

-
- -
+
+
+ +

Keep LED on constantly

+
+ +
+
+
- + + + + + Touch & Timing + + Configure interaction timeouts + + +
+ + +
+
+
-
- - -
- - - - - -
- {/if} + + + + + Device Options + + Toggle advanced features + + +
+
+ +

Restart device on reset

+
+ +
- {#if currentView === "logs"} -
-
-
-

System Logs

-

- Real-time device communication and application events. -

-
- -
+
+
+ +

Does not work on Android!

+
+ +
+ + +
- - - {#if logger.logs.length === 0} -
- -

No events recorded yet.

-
- {:else} - -
- {#each logger.logs as log} -
- [{log.timestamp}] - - {#if log.type === - "success"}➜ - {/if} - {#if log.type === - "error"}✖ - {/if} - {log.message} - -
- {/each} -
-
- {/if} -
-
-
- {/if} +
+ +
+ {/if} +
+ {/if} - {#if currentView === "about"} -
-
-

About

-
+ {#if currentView === "security"} +
+
+

Secure Boot

+

+ Permanently lock this device to the current firmware vendor. +

+
- - -
-
- PicoForge Logo -
+ + + Feature Unstable + + This feature is currently under work and disabled for safety. + + -

PicoForge

- v0.1.1-Alpha -

- An open source commissioning tool for Pico FIDO security keys. Developed with Rust, Tauri, and - Svelte. -

+ + + Lock Settings + + +
+
+ +

+ Verifies firmware signature on startup +

+
+ +
-
-
- Code By: Suyog Tandel -
-
- Artwork: Suyog Tandel -
-
- - Copyright: - 2026 Suyog Tandel -
-
+
+
+ +

+ Prevents reading key material via debug ports +

+
+ +
-
- - -
-
-
-
-
- {/if} -
-
-
-
-
+ - - - - {dialogTitle} - - {dialogMessage} - - - - dialogOpen = false}>Okay - - - -
+
+ + +
+ + + + + +
+ {/if} + + {#if currentView === "logs"} +
+
+
+

System Logs

+

+ Real-time device communication and application events. +

+
+ +
+ + + + {#if logger.logs.length === 0} +
+ +

No events recorded yet.

+
+ {:else} + +
+ {#each logger.logs as log} +
+ [{log.timestamp}] + + {#if log.type === "success"}➜{/if} + {#if log.type === "error"}✖{/if} + {log.message} + +
+ {/each} +
+
+ {/if} +
+
+
+ {/if} + + {#if currentView === "about"} +
+
+

About

+
+ + + +
+
+ PicoForge Logo +
+ +

PicoForge

+ v0.1.1-Alpha +

+ An open source commissioning tool for Pico FIDO security keys. Developed with Rust, Tauri, and + Svelte. +

+ +
+
+ Code By: Suyog Tandel +
+
+ Artwork: Suyog Tandel +
+
+ + Copyright: + 2026 Suyog Tandel +
+
+ +
+ + +
+
+
+
+
+ {/if} +
+ + + + + + + + + {dialogTitle} + + {dialogMessage} + + + + dialogOpen = false}>Okay + + + + + + + + {isSettingPin ? "Set PIN" : "Change PIN"} + + {isSettingPin + ? "Set a PIN for your FIDO2 device. Minimum length is " + (device.fidoInfo?.minPinLength || 4) + " characters." + : "Enter your current PIN and choose a new one."} + + +
+ {#if !isSettingPin} +
+ + +
+ {/if} +
+ + +
+
+ + +
+ {#if pinError} +

{pinError}

+ {/if} +
+ + pinDialogOpen = false}>Cancel + Confirm + +
+
+ + + + + Update Minimum PIN Length + + Set the minimum allowed PIN length (4-63 characters) and enter a new PIN that meets this requirement. + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ {#if minPinError} +

{minPinError}

+ {/if} +
+ + minPinDialogOpen = false}>Cancel + Update + +
+
+ \ No newline at end of file