File: cards.rs

package info (click to toggle)
rust-openpgp-card-rpgp 0.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 392 kB
  • sloc: sh: 6; makefile: 2
file content (141 lines) | stat: -rw-r--r-- 3,990 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// SPDX-FileCopyrightText: Heiko Schaefer <heiko@schaefer.name>
// 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<ShareMode> = Some(ShareMode::Shared);

#[derive(Debug, Deserialize)]
pub struct TestConfig {
    card: BTreeMap<String, Card>,
}

#[derive(Debug, Deserialize)]
pub struct Card {
    backend: BTreeMap<String, String>,
    config: Config,
}

#[derive(Clone, Debug, Deserialize)]
pub struct Config {
    pub keygen: Option<Vec<String>>,
    pub import: Option<Vec<String>>,
}

/// 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<openpgp_card::Card<Open>> {
        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<Self> {
        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<TestCardData> {
        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<openpgp_card::Card<Open>> {
        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<openpgp_card::Card<Open>, Error> = loop {
                    i += 1;

                    let cards = PcscBackend::card_backends(None)?;
                    let res = openpgp_card::Card::<Open>::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::<Open>::new(backend)?)
            }
        }
    }
}