mirror of
https://github.com/librekeys/picoforge.git
synced 2026-07-28 08:01:19 -07:00
support pico-fido version 7.4
This commit is contained in:
@@ -182,6 +182,54 @@ impl VendorConfigCommand {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum FidoCertification {
|
||||
AuthEncryption,
|
||||
AuthEncryptionLock,
|
||||
EnterpriseAttestation,
|
||||
PinComplexity,
|
||||
PhysicalVidPid,
|
||||
LedBrightness,
|
||||
LedGpio,
|
||||
PhysicalOptions,
|
||||
}
|
||||
|
||||
impl FidoCertification {
|
||||
pub fn from_u64(val: u64) -> Option<Self> {
|
||||
match val {
|
||||
0x03E43F56B34285E2 => Some(Self::AuthEncryption),
|
||||
0x1831A40F04A25ED9 => Some(Self::AuthEncryptionLock),
|
||||
0x66F2A674C29A8DCF => Some(Self::EnterpriseAttestation),
|
||||
0x6C07D70FE96C3897 => Some(Self::PinComplexity),
|
||||
0x6FCB19B0CBE3ACFA => Some(Self::PhysicalVidPid),
|
||||
0x76A85945985D02FD => Some(Self::LedBrightness),
|
||||
0x7B392A394DE9F948 => Some(Self::LedGpio),
|
||||
0x269F3B09ECEB805F => Some(Self::PhysicalOptions),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(val: &str) -> Option<Self> {
|
||||
let val = val.strip_prefix("0x").unwrap_or(val);
|
||||
u64::from_str_radix(val, 16).ok().and_then(Self::from_u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FidoCertification {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::AuthEncryption => write!(f, "Auth Encryption"),
|
||||
Self::AuthEncryptionLock => write!(f, "Auth Encryption (Lock)"),
|
||||
Self::EnterpriseAttestation => write!(f, "Enterprise Attestation"),
|
||||
Self::PinComplexity => write!(f, "PIN Complexity"),
|
||||
Self::PhysicalVidPid => write!(f, "Physical VID/PID"),
|
||||
Self::LedBrightness => write!(f, "LED Brightness"),
|
||||
Self::LedGpio => write!(f, "LED GPIO"),
|
||||
Self::PhysicalOptions => write!(f, "Physical Options"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for VendorConfigCommand {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
@@ -288,6 +336,55 @@ pub enum CoseAlgorithm {
|
||||
ESB512 = -268,
|
||||
}
|
||||
|
||||
impl CoseAlgorithm {
|
||||
pub fn from_i128(val: i128) -> Option<Self> {
|
||||
match val as i32 {
|
||||
-7 => Some(Self::ES256),
|
||||
-8 => Some(Self::EdDSA),
|
||||
-9 => Some(Self::ESP256),
|
||||
-19 => Some(Self::Ed25519),
|
||||
-25 => Some(Self::EcdhEsHkdf256),
|
||||
-35 => Some(Self::ES384),
|
||||
-36 => Some(Self::ES512),
|
||||
-47 => Some(Self::ES256K),
|
||||
-51 => Some(Self::ESP384),
|
||||
-52 => Some(Self::ESP512),
|
||||
-53 => Some(Self::Ed448),
|
||||
-257 => Some(Self::RS256),
|
||||
-258 => Some(Self::RS384),
|
||||
-259 => Some(Self::RS512),
|
||||
-265 => Some(Self::ESB256),
|
||||
-267 => Some(Self::ESB384),
|
||||
-268 => Some(Self::ESB512),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CoseAlgorithm {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::ES256 => write!(f, "ES256"),
|
||||
Self::EdDSA => write!(f, "EdDSA"),
|
||||
Self::ESP256 => write!(f, "ESP256"),
|
||||
Self::Ed25519 => write!(f, "Ed25519"),
|
||||
Self::EcdhEsHkdf256 => write!(f, "ECDH-ES-HKDF-256"),
|
||||
Self::ES384 => write!(f, "ES384"),
|
||||
Self::ES512 => write!(f, "ES512"),
|
||||
Self::ES256K => write!(f, "ES256K"),
|
||||
Self::ESP384 => write!(f, "ESP384"),
|
||||
Self::ESP512 => write!(f, "ESP512"),
|
||||
Self::Ed448 => write!(f, "Ed448"),
|
||||
Self::RS256 => write!(f, "RS256"),
|
||||
Self::RS384 => write!(f, "RS384"),
|
||||
Self::RS512 => write!(f, "RS512"),
|
||||
Self::ESB256 => write!(f, "ESB256"),
|
||||
Self::ESB384 => write!(f, "ESB384"),
|
||||
Self::ESB512 => write!(f, "ESB512"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum CoseCurve {
|
||||
|
||||
+406
-31
File diff suppressed because it is too large
Load Diff
@@ -228,8 +228,8 @@ pub fn read_device_details() -> Result<FullDeviceStatus, PFError> {
|
||||
Ok(FullDeviceStatus {
|
||||
info: DeviceInfo {
|
||||
serial: serial_str,
|
||||
flash_used: used / 1024,
|
||||
flash_total: total / 1024,
|
||||
flash_used: Some(used / 1024),
|
||||
flash_total: Some(total / 1024),
|
||||
firmware_version: format!("{}.{}", version_major, version_minor),
|
||||
},
|
||||
config,
|
||||
|
||||
+15
-5
@@ -10,8 +10,8 @@ struct PForgeState {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeviceInfo {
|
||||
pub serial: String,
|
||||
pub flash_used: u32,
|
||||
pub flash_total: u32,
|
||||
pub flash_used: Option<u32>,
|
||||
pub flash_total: Option<u32>,
|
||||
pub firmware_version: String,
|
||||
}
|
||||
|
||||
@@ -74,11 +74,21 @@ pub struct FidoDeviceInfo {
|
||||
pub extensions: Vec<String>,
|
||||
pub aaguid: String,
|
||||
pub options: std::collections::HashMap<String, bool>,
|
||||
pub max_msg_size: i32,
|
||||
pub max_msg_size: i128,
|
||||
pub pin_protocols: Vec<u32>,
|
||||
// pub remaining_disc_creds: u32,
|
||||
pub min_pin_length: u32,
|
||||
pub remaining_discoverable_credentials: Option<i128>,
|
||||
pub min_pin_length: i128,
|
||||
pub firmware_version: String,
|
||||
/// Supported vendor config commands (human-readable names), parsed from CTAP GetInfo key 0x13
|
||||
pub vendor_config_commands: Vec<String>,
|
||||
/// Device certifications, parsed from CTAP GetInfo key 0x15
|
||||
pub certifications: std::collections::HashMap<String, bool>,
|
||||
pub max_credential_count_in_list: Option<i128>,
|
||||
pub max_credential_id_length: Option<i128>,
|
||||
pub algorithms: Vec<String>,
|
||||
pub max_serialized_large_blob_array: Option<i128>,
|
||||
pub force_pin_change: Option<bool>,
|
||||
pub max_cred_blob_length: Option<i128>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
|
||||
@@ -15,6 +15,33 @@ enum DialogPhase {
|
||||
Error(String),
|
||||
}
|
||||
|
||||
fn render_error_message(msg: String) -> impl IntoElement {
|
||||
let troubleshooting_phrase = "troubleshooting guide";
|
||||
let url = "https://github.com/librekeys/picoforge/wiki/Troubleshooting#1-my-key-is-not-detected-by-picoforge-or-picoforge-displays-a-device-status-of-online---fido-and-there-are-some-settings-that-i-cannot-configure";
|
||||
|
||||
if msg.contains(troubleshooting_phrase) {
|
||||
v_flex()
|
||||
.child("The device firmware does not support being configured in fido only communication mode.")
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.child("Have a look at the")
|
||||
.child(
|
||||
div()
|
||||
.text_color(rgb(0x3b82f6))
|
||||
.cursor_pointer()
|
||||
.on_mouse_down(MouseButton::Left, move |_, _, cx| {
|
||||
cx.open_url(url);
|
||||
})
|
||||
.child(troubleshooting_phrase.to_string()),
|
||||
)
|
||||
.child("to fix this"),
|
||||
)
|
||||
} else {
|
||||
div().child(msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PinPromptContent {
|
||||
phase: DialogPhase,
|
||||
title: SharedString,
|
||||
@@ -120,7 +147,7 @@ impl Render for PinPromptContent {
|
||||
.bg(cx.theme().danger.opacity(0.1))
|
||||
.text_color(cx.theme().danger)
|
||||
.text_sm()
|
||||
.child(err_msg.clone()),
|
||||
.child(render_error_message(err_msg.clone())),
|
||||
)
|
||||
.child(Input::new(&pin_input))
|
||||
.child(
|
||||
@@ -329,7 +356,7 @@ impl Render for ConfirmContent {
|
||||
.bg(cx.theme().danger.opacity(0.1))
|
||||
.text_color(cx.theme().danger)
|
||||
.text_sm()
|
||||
.child(err_msg.clone()),
|
||||
.child(render_error_message(err_msg.clone())),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
@@ -551,7 +578,7 @@ impl Render for ChangePinContent {
|
||||
.bg(cx.theme().danger.opacity(0.1))
|
||||
.text_color(cx.theme().danger)
|
||||
.text_sm()
|
||||
.child(err_msg.clone()),
|
||||
.child(render_error_message(err_msg.clone())),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
@@ -859,7 +886,7 @@ impl Render for SetPinContent {
|
||||
.bg(cx.theme().danger.opacity(0.1))
|
||||
.text_color(cx.theme().danger)
|
||||
.text_sm()
|
||||
.child(err_msg.clone()),
|
||||
.child(render_error_message(err_msg.clone())),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
@@ -1094,7 +1121,7 @@ impl Render for StatusContent {
|
||||
.bg(cx.theme().danger.opacity(0.1))
|
||||
.text_color(cx.theme().danger)
|
||||
.text_sm()
|
||||
.child(err_msg.clone()),
|
||||
.child(render_error_message(err_msg.clone())),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
|
||||
+14
-3
@@ -228,11 +228,12 @@ impl ConfigView {
|
||||
cx.notify();
|
||||
|
||||
let entity = cx.entity().downgrade();
|
||||
let method_clone = method.clone();
|
||||
|
||||
self._task = Some(cx.spawn(async move |_, cx| {
|
||||
let result = cx
|
||||
.background_executor()
|
||||
.spawn(async move { io::write_config(changes, method, pin) })
|
||||
.spawn(async move { io::write_config(changes, method_clone, pin) })
|
||||
.await;
|
||||
|
||||
let new_status_result = if result.is_ok() {
|
||||
@@ -289,15 +290,25 @@ impl ConfigView {
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Error saving config: {}", e);
|
||||
|
||||
let mut err_msg = format!("Failed to apply configuration: {}", e);
|
||||
|
||||
// Special case for FIDO 0x3E error (Invalid Subcommand)
|
||||
// This happens when the firmware is too old to support config over FIDO
|
||||
if method == crate::device::types::DeviceMethod::Fido && err_msg.contains("0x3E")
|
||||
{
|
||||
err_msg = "The device firmware does not support being configured in fido only communication mode. \nHave a look at the troubleshooting guide to fix this".to_string();
|
||||
}
|
||||
|
||||
match &dialog_handle {
|
||||
StatusDialogHandle::Pin(dh) => {
|
||||
let _ = dh.update(cx, |d, cx| {
|
||||
d.set_error(format!("Failed to apply: {}", e), cx);
|
||||
d.set_error(err_msg, cx);
|
||||
});
|
||||
}
|
||||
StatusDialogHandle::Status(dh) => {
|
||||
let _ = dh.update(cx, |d, cx| {
|
||||
d.set_error(format!("Failed to apply: {}", e), cx);
|
||||
d.set_error(err_msg, cx);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+66
-8
@@ -1,6 +1,7 @@
|
||||
use crate::device::types::DeviceMethod;
|
||||
use crate::ui::components::{card::Card, page_view::PageView, tag::Tag};
|
||||
use crate::ui::types::GlobalDeviceState;
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::*;
|
||||
use gpui_component::StyledExt;
|
||||
use gpui_component::{Icon, IconName, Theme, h_flex, progress::Progress, v_flex};
|
||||
@@ -86,8 +87,6 @@ impl HomeView {
|
||||
let info = &status.info;
|
||||
let config = &status.config;
|
||||
|
||||
let flash_percent = (info.flash_used as f32 / info.flash_total as f32) * 100.0;
|
||||
|
||||
Card::new()
|
||||
.title("Device Information")
|
||||
.icon(Icon::default().path("icons/cpu.svg"))
|
||||
@@ -137,12 +136,25 @@ impl HomeView {
|
||||
.text_color(theme.muted_foreground)
|
||||
.child("Flash Memory"),
|
||||
)
|
||||
.child(div().text_color(theme.foreground).child(format!(
|
||||
"{:.0} / {:.0} KB",
|
||||
info.flash_used, info.flash_total
|
||||
))),
|
||||
.child(div().text_color(theme.foreground).child(
|
||||
if let (Some(used), Some(total)) =
|
||||
(info.flash_used, info.flash_total)
|
||||
{
|
||||
format!("{:.0} / {:.0} KB", used, total)
|
||||
} else {
|
||||
"Not Available".to_string()
|
||||
},
|
||||
)),
|
||||
)
|
||||
.child(Progress::new().value(flash_percent)),
|
||||
.when(
|
||||
info.flash_used.is_some() && info.flash_total.is_some(),
|
||||
|this| {
|
||||
let used = info.flash_used.unwrap();
|
||||
let total = info.flash_total.unwrap();
|
||||
let flash_percent = (used as f32 / total as f32) * 100.0;
|
||||
this.child(Progress::new().value(flash_percent))
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -190,10 +202,56 @@ impl HomeView {
|
||||
},
|
||||
theme,
|
||||
false,
|
||||
)),
|
||||
))
|
||||
.when(fido.remaining_discoverable_credentials.is_some(), |this| {
|
||||
this.child(Self::render_kv(
|
||||
"Remaining Credentials",
|
||||
fido.remaining_discoverable_credentials
|
||||
.unwrap_or(0)
|
||||
.to_string(),
|
||||
theme,
|
||||
false,
|
||||
))
|
||||
}),
|
||||
)
|
||||
.child(div().h_px().bg(theme.border))
|
||||
.child(Self::render_kv("AAGUID", fido.aaguid.clone(), theme, true))
|
||||
// .when(!fido.vendor_config_commands.is_empty(), |this| {
|
||||
// this.child(div().h_px().bg(theme.border)).child(
|
||||
// v_flex()
|
||||
// .gap_2()
|
||||
// .child(
|
||||
// div()
|
||||
// .text_sm()
|
||||
// .text_color(theme.muted_foreground)
|
||||
// .child("Vendor Config Commands"),
|
||||
// )
|
||||
// .child(
|
||||
// h_flex().gap_2().flex_wrap().children(
|
||||
// fido.vendor_config_commands
|
||||
// .iter()
|
||||
// .map(|cmd| Tag::new(cmd.clone()).active(true)),
|
||||
// ),
|
||||
// ),
|
||||
// )
|
||||
// })
|
||||
// .when(!fido.certifications.is_empty(), |this| {
|
||||
// this.child(div().h_px().bg(theme.border)).child(
|
||||
// v_flex()
|
||||
// .gap_2()
|
||||
// .child(
|
||||
// div()
|
||||
// .text_sm()
|
||||
// .text_color(theme.muted_foreground)
|
||||
// .child("Certifications"),
|
||||
// )
|
||||
// .child(h_flex().gap_2().flex_wrap().children(
|
||||
// fido.certifications.iter().map(|(name, _enabled)| {
|
||||
// Tag::new(name.clone()).active(true)
|
||||
// }),
|
||||
// )),
|
||||
// )
|
||||
// })
|
||||
.into_any_element()
|
||||
} else {
|
||||
div()
|
||||
|
||||
Reference in New Issue
Block a user