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<Mutex<HidApi>> = Lazy::new(|| {
HidApi::new()
.expect("failed to create hidapi instance")
.into()
});
fn with_device<F: Fn(&Device<HidDevice>)>(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<u8, Value> =
serde_cbor::from_slice(&response).expect("failed to parse ctap2 response");
assert!(data.contains_key(&0x03), "{:?}", data);
});
}