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
#[cfg(not(debug_assertions))]
compile_error!("MockHsm is not intended for use in release builds");

use std::{
    str::FromStr,
    sync::{Arc, Mutex},
};

mod audit;
mod command;
mod connection;
mod object;
mod session;
mod state;

pub use self::connection::MockConnection;
use self::state::State;
use connector::{Connection, ConnectionError, Connector};
use serial_number::SerialNumber;

/// Mock serial number for the MockHsm
pub const MOCK_SERIAL_NUMBER: &str = "0123456789";

/// Software simulation of a `YubiHSM2` intended for testing
/// implemented as a `yubihsm::Connection`.
///
/// This only implements a subset of the YubiHSM's functionality, and does
/// not enforce access control. It's recommended to also test live against
/// a real device.
///
/// To enable, make sure to build yubihsm.rs with the `mockhsm` cargo feature
#[derive(Clone, Debug)]
pub struct MockHsm(Arc<Mutex<State>>);

impl MockHsm {
    /// Create a new MockHsm
    pub fn new() -> Self {
        MockHsm(Arc::new(Mutex::new(State::new())))
    }
}

impl Connector for MockHsm {
    /// Create a new connection with a clone of the MockHsm state
    fn connect(&self) -> Result<Box<Connection>, ConnectionError> {
        Ok(Box::new(MockConnection::new(self)))
    }

    /// Rust never sleeps
    fn healthcheck(&self) -> Result<(), ConnectionError> {
        Ok(())
    }

    /// Get the serial number for the current YubiHSM2 (if available)
    fn serial_number(&self) -> Result<SerialNumber, ConnectionError> {
        Ok(SerialNumber::from_str(MOCK_SERIAL_NUMBER).unwrap())
    }
}

impl Default for MockHsm {
    fn default() -> Self {
        Self::new()
    }
}

impl Into<Box<Connector>> for MockHsm {
    fn into(self) -> Box<Connector> {
        Box::new(self)
    }
}