// Copyright (C) 2022 Robin Krahl // SPDX-License-Identifier: CC0-1.0 // The tests in this module are ignored as they require a connected CTAPHID device. use std::{collections::BTreeMap, sync::Mutex}; use ctaphid::Device; use hidapi::{HidApi, HidDevice}; use once_cell::sync::Lazy; use serde_cbor::Value; static HIDAPI: Lazy> = Lazy::new(|| { HidApi::new() .expect("failed to create hidapi instance") .into() }); fn with_device)>(f: F) { let hidapi = match HIDAPI.lock() { Ok(hidapi) => hidapi, Err(error) => error.into_inner(), }; let devices = hidapi .device_list() .filter(|device| ctaphid::is_known_device(*device)); for device_info in devices { let hid_device = device_info .open_device(&hidapi) .expect("failed to open hidapi device"); let device = Device::new(hid_device, device_info.to_owned()).expect("failed to open ctaphid device"); println!("{:?}", device); f(&device); } } #[test] #[ignore] fn init() { with_device(|_| {}); } #[test] #[ignore] fn ping() { with_device(|device| { let result = device.ping(&[0xde, 0xad, 0xbe, 0xef]); assert!(result.is_ok(), "{:?}", result); }); } #[test] #[ignore] fn ctap1() { with_device(|device| { assert!( device.capabilities().has_msg(), "{:?}", device.capabilities() ); let response = device .ctap1(&[0x00, 0x03, 0x00, 0x00, 0x00]) .expect("failed to execute ctap1 command"); let n = response.len(); assert!(n > 2, "{}", n); assert_eq!(&response[n - 2..], &[0x90, 0x00]); let version = String::from_utf8_lossy(&response[..n - 2]); assert!(version.starts_with("U2F"), "{}", version); }); } #[test] #[ignore] fn ctap2() { with_device(|device| { assert!( device.capabilities().has_cbor(), "{:?}", device.capabilities() ); let response = device .ctap2(0x04, &[]) .expect("failed to execute ctap2 command"); let data: BTreeMap = serde_cbor::from_slice(&response).expect("failed to parse ctap2 response"); assert!(data.contains_key(&0x03), "{:?}", data); }); }