// SPDX-FileCopyrightText: Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 //! Wrapping of cards for tests. Open a list of cards, based on a //! TestConfig configuration file use std::collections::BTreeMap; use anyhow::Result; use card_backend_pcsc::PcscBackend; use card_backend_scdc::ScdBackend; use openpgp_card::state::Open; use openpgp_card::Error; use serde::Deserialize; // const SHARE_MODE: Option = Some(ShareMode::Shared); #[derive(Debug, Deserialize)] pub struct TestConfig { card: BTreeMap, } #[derive(Debug, Deserialize)] pub struct Card { backend: BTreeMap, config: Config, } #[derive(Clone, Debug, Deserialize)] pub struct Config { pub keygen: Option>, pub import: Option>, } /// An "opened" card, via one particular backend, with test-metadata #[derive(Debug)] pub struct TestCardData { name: String, tc: TestCard, config: Config, } impl TestCardData { pub fn get_card(&self) -> Result> { self.tc.open() } pub fn get_config(&self) -> &Config { &self.config } pub fn get_name(&self) -> &str { &self.name } } impl TestConfig { pub fn load(file: &str) -> Result { let config_file = std::fs::read_to_string(file)?; let config: Self = toml::from_str(&config_file)?; Ok(config) } pub fn into_cardapps(self) -> Vec { let mut cards = vec![]; for (name, card) in self.card { for (backend, id) in &card.backend { let tc: TestCard = match backend.as_str() { "pcsc" => TestCard::Pcsc(id.to_string()), "scdc" => TestCard::Scdc(id.to_string()), _ => panic!("unexpected backend {}", backend), }; cards.push(TestCardData { name: name.clone(), tc, config: card.config.clone(), }) } } cards } } #[derive(Debug)] pub enum TestCard { Pcsc(String), Scdc(String), } impl TestCard { pub fn open(&self) -> Result> { match self { Self::Pcsc(ident) => { // Attempt to shutdown SCD, if it is running. // Ignore any errors that occur during that shutdown attempt. let res = ScdBackend::shutdown_scd(None); log::trace!(" Attempt to shutdown scd: {:?}", res); // Make three attempts to open the card before failing // (this can be useful in ShareMode::Exclusive) let mut i = 1; let card: Result, Error> = loop { i += 1; let cards = PcscBackend::card_backends(None)?; let res = openpgp_card::Card::::open_by_ident(cards, ident); println!("Got result for card: {}", ident); if let Err(e) = &res { println!("Result is an error: {:x?}", e); } else { println!("Result is a happy card"); } if let Ok(res) = res { break Ok(res); } if i > 3 { break Err(Error::NotFound(format!("Couldn't open card {}", ident))); } // sleep for 100ms println!("Will sleep for 100ms"); std::thread::sleep(std::time::Duration::from_millis(100)); }; Ok(card?) } Self::Scdc(serial) => { let backend = ScdBackend::open_by_serial(None, serial)?; Ok(openpgp_card::Card::::new(backend)?) } } } }