From f57c373faa2b533d3f311fedd267978b92bb0b74 Mon Sep 17 00:00:00 2001 From: pjht Date: Wed, 16 Aug 2023 11:58:15 -0500 Subject: [PATCH] Add support for choosing between multiple authenticators --- src/main.rs | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 628e8e3..a917c75 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use std::{ fs::Permissions, os::unix::prelude::PermissionsExt, - path::{Path, PathBuf}, fmt::Display, + path::{Path, PathBuf}, fmt::Display, io::Write, }; use anyhow::anyhow; @@ -9,7 +9,7 @@ use bitflags::bitflags; use clap::{Parser, ValueEnum}; use ctap_hid_fido2::{ fidokey::{CredentialSupportedKeyType, MakeCredentialArgsBuilder}, - verifier, FidoKeyHidFactory, LibCfg, + verifier, LibCfg, get_fidokey_devices, FidoKeyHid, }; use ssh_encoding::{Decode, Encode, LineEnding}; use ssh_key::{private, PrivateKey}; @@ -89,11 +89,45 @@ fn main() -> anyhow::Result<()> { let challenge = verifier::create_challenge(); + + + let devices = get_fidokey_devices(); + let device = if devices.len() > 1 { + println!("Availible devices:"); + for (i, device) in devices.iter().enumerate() { + println!("\t{}: {}", i + 1, device.product_string); + } + let mut buf = String::new(); + loop { + print!("Device number: "); + std::io::stdout().flush()?; + buf.clear(); + std::io::stdin().read_line(&mut buf)?; + if let Ok(num) = buf.trim().parse::() { + if num == 0 { + println!("Invalid number"); + continue; + } + if let Some(device) = devices.get(num - 1) { + break device; + } else { + println!("Invalid number"); + continue; + } + } else { + println!("Invalid number"); + continue; + } + } + } else { + &devices[0] + }; + let mut libcfg = LibCfg::init(); libcfg.keep_alive_msg = "Touch the authenticator now.".into(); - let device = FidoKeyHidFactory::create(&libcfg)?; - - let device_has_pin = device.get_info()?.options.contains(&("clientPin".into(), true)); + let device = FidoKeyHid::new(&[device.param.clone()], &libcfg)?; + let device_has_pin = device.get_info().map_or(false, |info| info.options.contains(&("clientPin".into(), true))); + let pin = if device_has_pin { rpassword::prompt_password("Enter FIDO2 PIN: ")? } else {